summaryrefslogtreecommitdiff
path: root/hammer/op_output.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/op_output.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'hammer/op_output.cpp')
-rw-r--r--hammer/op_output.cpp2516
1 files changed, 2516 insertions, 0 deletions
diff --git a/hammer/op_output.cpp b/hammer/op_output.cpp
new file mode 100644
index 0000000..c5c9d8b
--- /dev/null
+++ b/hammer/op_output.cpp
@@ -0,0 +1,2516 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Implements a dialog for editing the input/output connections of a
+// list of entities. The connections are displayed in a grid control,
+// each row of the grid control representing a connection that is
+// common to all entities being edited. For example, given these two ents:
+//
+// Button01
+// OnDamaged Sound01 PlaySound 0 0
+// OnPressed Door01 Open 0 0
+//
+// Button02
+// OnPressed Door01 Open 0 0
+//
+// If these two entities were selected, the grid control would show:
+//
+// OnPressed Door01 Open 0 0
+//
+// because it is the only connection that is common to both entities.
+// Editing an entry in the grid control modifies the corresponding
+// connection in all selected entities.
+//
+// TODO: persist sort column index, sort directions, and column sizes
+// TODO: implement an external mode, where the grid shows all connections to unselected ents
+//
+//=============================================================================//
+
+#include "stdafx.h"
+#include "GlobalFunctions.h"
+#include "MapDoc.h"
+#include "MapEntity.h"
+#include "MapWorld.h"
+#include "ObjectProperties.h"
+#include "OP_Output.h"
+#include "ToolManager.h"
+#include "MainFrm.h"
+#include "utlrbtree.h"
+#include "options.h"
+#include ".\op_output.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+
+#pragma warning( disable : 4355 )
+
+
+#define ICON_CONN_BAD 0
+#define ICON_CONN_GOOD 1
+#define ICON_CONN_BAD_GREY 2
+#define ICON_CONN_GOOD_GREY 3
+
+
+const char *PARAM_STRING_NONE = "<none>";
+
+
+//
+// Column indices for the list control.
+//
+const int ICON_COLUMN = 0;
+const int OUTPUT_NAME_COLUMN = 1;
+const int TARGET_NAME_COLUMN = 2;
+const int INPUT_NAME_COLUMN = 3;
+const int PARAMETER_COLUMN = 4;
+const int DELAY_COLUMN = 5;
+const int ONLY_ONCE_COLUMN = 6;
+
+IMPLEMENT_DYNCREATE(COP_Output, CObjectPage)
+
+
+BEGIN_MESSAGE_MAP(COP_Output, CObjectPage)
+ //{{AFX_MSG_MAP(COP_Output)
+ ON_BN_CLICKED(IDC_ADD, OnAdd)
+ ON_BN_CLICKED(IDC_DELETE, OnDelete)
+ ON_BN_CLICKED(IDC_COPY, OnCopy)
+ ON_WM_SIZE()
+ ON_BN_CLICKED(IDC_PASTE, OnPaste)
+ ON_BN_CLICKED(IDC_MARK, OnMark)
+ ON_BN_CLICKED(IDC_PICK_ENTITY, OnPickEntity)
+ ON_BN_CLICKED(IDC_PICK_ENTITY_PARAM, OnPickEntityParam)
+ ON_CBN_SELCHANGE(IDC_EDIT_CONN_INPUT, OnSelChangeInput)
+ ON_CBN_EDITUPDATE(IDC_EDIT_CONN_INPUT, OnEditUpdateInput)
+ ON_CBN_SELCHANGE(IDC_EDIT_CONN_OUTPUT, OnSelChangeOutput)
+ ON_CBN_EDITUPDATE(IDC_EDIT_CONN_OUTPUT, OnEditUpdateOutput)
+ ON_CBN_SELCHANGE(IDC_EDIT_CONN_PARAM, OnSelChangeParam)
+ ON_CBN_EDITUPDATE(IDC_EDIT_CONN_PARAM, OnEditUpdateParam)
+ ON_EN_CHANGE(IDC_EDIT_CONN_DELAY, OnEditDelay)
+ ON_BN_CLICKED(IDC_EDIT_CONN_FIRE_ONCE, OnFireOnce)
+ ON_BN_CLICKED(IDC_SHOWHIDDENTARGETS, OnShowHiddenTargetsAsBroken)
+ ON_WM_DESTROY()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+// ON_CBN_SELCHANGE(IDC_EDIT_CONN_TARGET, OnSelChangeTarget)
+// ON_CBN_EDITUPDATE(IDC_EDIT_CONN_TARGET, OnEditUpdateTarget)
+
+
+//
+// Static data.
+//
+CEntityConnectionList *COP_Output::m_pConnectionBuffer = new CEntityConnectionList;
+CImageList *COP_Output::m_pImageList = NULL;
+
+
+//-----------------------------------------------------------------------------
+// Returns true if any of the target entities in the connection list are visible.
+//-----------------------------------------------------------------------------
+static bool AreAnyTargetEntitiesVisible( CEntityConnectionList *pList )
+{
+ for ( int i=0; i < pList->Count(); i++ )
+ {
+ if ( pList->Element(i)->AreAnyTargetEntitiesVisible() )
+ return true;
+ }
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Compares by delays. Used as a secondary sort by all other columns.
+//-----------------------------------------------------------------------------
+static int CALLBACK ListCompareDelaysSecondary(COutputConnection *pOutputConn1, COutputConnection *pOutputConn2, SortDirection_t eDirection)
+{
+ CEntityConnectionList *pConnList1 = pOutputConn1->m_pConnList;
+ CEntityConnectionList *pConnList2 = pOutputConn2->m_pConnList;
+ CEntityConnection *pConn1 = pConnList1->Element(0);
+ CEntityConnection *pConn2 = pConnList2->Element(0);
+ return CEntityConnection::CompareDelaysSecondary(pConn1,pConn2,eDirection);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Compares by delays, does a secondary compare by output name.
+//-----------------------------------------------------------------------------
+static int CALLBACK ListCompareDelays(COutputConnection *pOutputConn1, COutputConnection *pOutputConn2, SortDirection_t eDirection)
+{
+ CEntityConnectionList *pConnList1 = pOutputConn1->m_pConnList;
+ CEntityConnectionList *pConnList2 = pOutputConn2->m_pConnList;
+ CEntityConnection *pConn1 = pConnList1->Element(0);
+ CEntityConnection *pConn2 = pConnList2->Element(0);
+ return CEntityConnection::CompareDelays(pConn1,pConn2,eDirection);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Compares by output name, does a secondary compare by delay.
+//-----------------------------------------------------------------------------
+static int CALLBACK ListCompareOutputNames(COutputConnection *pOutputConn1, COutputConnection *pOutputConn2, SortDirection_t eDirection)
+{
+ CEntityConnectionList *pConnList1 = pOutputConn1->m_pConnList;
+ CEntityConnectionList *pConnList2 = pOutputConn2->m_pConnList;
+ CEntityConnection *pConn1 = pConnList1->Element(0);
+ CEntityConnection *pConn2 = pConnList2->Element(0);
+ return CEntityConnection::CompareOutputNames(pConn1,pConn2,eDirection);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Compares by input name, does a secondary compare by delay.
+//-----------------------------------------------------------------------------
+static int CALLBACK ListCompareInputNames(COutputConnection *pOutputConn1, COutputConnection *pOutputConn2, SortDirection_t eDirection)
+{
+ CEntityConnectionList *pConnList1 = pOutputConn1->m_pConnList;
+ CEntityConnectionList *pConnList2 = pOutputConn2->m_pConnList;
+ CEntityConnection *pConn1 = pConnList1->Element(0);
+ CEntityConnection *pConn2 = pConnList2->Element(0);
+ return (CEntityConnection::CompareInputNames(pConn1,pConn2,eDirection));
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Compares by source name, does a secondary compare by delay.
+//-----------------------------------------------------------------------------
+static int CALLBACK ListCompareSourceNames(COutputConnection *pOutputConn1, COutputConnection *pOutputConn2, SortDirection_t eDirection)
+{
+ CEntityConnectionList *pConnList1 = pOutputConn1->m_pConnList;
+ CEntityConnectionList *pConnList2 = pOutputConn2->m_pConnList;
+ CEntityConnection *pConn1 = pConnList1->Element(0);
+ CEntityConnection *pConn2 = pConnList2->Element(0);
+ return (CEntityConnection::CompareSourceNames(pConn1,pConn2,eDirection));
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Compares by target name, does a secondary compare by delay.
+//-----------------------------------------------------------------------------
+static int CALLBACK ListCompareTargetNames(COutputConnection *pOutputConn1, COutputConnection *pOutputConn2, SortDirection_t eDirection)
+{
+ CEntityConnectionList *pConnList1 = pOutputConn1->m_pConnList;
+ CEntityConnectionList *pConnList2 = pOutputConn2->m_pConnList;
+ CEntityConnection *pConn1 = pConnList1->Element(0);
+ CEntityConnection *pConn2 = pConnList2->Element(0);
+ return (CEntityConnection::CompareTargetNames(pConn1,pConn2,eDirection));
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called by the entity picker tool when an entity is picked. This
+// stuffs the entity name into the smartedit control.
+//-----------------------------------------------------------------------------
+void COP_OutputPickEntityTarget::OnNotifyPickEntity(CToolPickEntity *pTool)
+{
+ //
+ // Update the edit control text with the entity name. This text will be
+ // stuffed into the local keyvalue storage in OnChangeSmartControl.
+ //
+ CMapEntityList Full;
+ CMapEntityList Partial;
+ pTool->GetSelectedEntities(Full, Partial);
+ CMapEntity *pEntity = Full.Element(0);
+ if (pEntity)
+ {
+ const char *pszName = pEntity->GetKeyValue("targetname");
+ if (!pszName)
+ {
+ pszName = "";
+ }
+
+ switch ( m_nDlgItem )
+ {
+ case IDC_EDIT_CONN_TARGET:
+ {
+ // FIXME: this should be called automatically, but it isn't
+ m_pDlg->m_ComboTarget.SelectItem(pszName);
+ break;
+ }
+
+ case IDC_EDIT_CONN_PARAM:
+ {
+ // FIXME: this should be called automatically, but it isn't
+ m_pDlg->GetDlgItem(m_nDlgItem)->SetWindowText(pszName);
+ m_pDlg->OnEditUpdateParam();
+ break;
+ }
+
+ default:
+ {
+ m_pDlg->GetDlgItem(m_nDlgItem)->SetWindowText(pszName);
+ break;
+ }
+ }
+ }
+
+ m_pDlg->StopPicking();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor.
+//-----------------------------------------------------------------------------
+COP_Output::COP_Output(void)
+ : CObjectPage(COP_Output::IDD), m_ComboTarget( this )
+{
+ m_bIgnoreTextChanged = false;
+ m_pObjectList = NULL;
+ m_pEditObjectRuntimeClass = RUNTIME_CLASS(editCMapClass);
+ m_nSortColumn = OUTPUT_NAME_COLUMN;
+ m_pMapEntityList = NULL;
+ m_fDelay = 0;
+ m_bPickingEntities = false;
+
+ bSkipEditControlRefresh = false;
+ //
+ // All columns initially sort in ascending order.
+ //
+ for (int i = 0; i < OUTPUT_LIST_NUM_COLUMNS; i++)
+ {
+ m_eSortDirection[i] = Sort_Ascending;
+ }
+
+ m_PickEntityTarget.AttachEntityDlg(this);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor.
+//-----------------------------------------------------------------------------
+COP_Output::~COP_Output(void)
+{
+}
+
+
+void COP_Output::OnTextChanged( const char *pText )
+{
+ if ( m_bIgnoreTextChanged )
+ return;
+
+ // Updating the listbox data, will trigger the edit
+ // controls to update. They don't need to be
+ bSkipEditControlRefresh = true;
+
+ // Target has changed so we need to update for list of inputs
+ // that are valid for this target
+ FillInputList();
+ FilterInputList();
+
+ m_ComboInput.SetWindowText(m_strInput);
+
+ UpdateEditedTargets();
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose: Updates the validity flag on the given item in the list control
+// Input : nItem -
+//------------------------------------------------------------------------------
+void COP_Output::UpdateItemValidity(int nItem)
+{
+ COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
+ CEntityConnectionList *pConnectionList = pOutputConn->m_pConnList;
+ bool bShared = (m_EntityList.Count() == pConnectionList->Count());
+
+ bool bShowHiddenTargets = ShouldShowHiddenTargets();
+
+ int nIcon;
+ if (ValidateConnections(pOutputConn, bShowHiddenTargets))
+ {
+ if ( !bShowHiddenTargets && !AreAnyTargetEntitiesVisible( pConnectionList ) )
+ nIcon = ICON_CONN_GOOD_GREY;
+ else if ( bShared )
+ nIcon = ICON_CONN_GOOD;
+ else
+ nIcon = ICON_CONN_GOOD_GREY;
+
+ pOutputConn->m_bIsValid = true;
+ }
+ else
+ {
+ nIcon = (bShared ? ICON_CONN_BAD : ICON_CONN_BAD_GREY);
+ pOutputConn->m_bIsValid = false;
+ }
+ m_ListCtrl.SetItem(nItem,0,LVIF_IMAGE, 0, nIcon, 0, 0, 0 );
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose :
+//------------------------------------------------------------------------------
+void COP_Output::UpdateValidityButton(void)
+{
+ CObjectProperties *pParent = (CObjectProperties*) GetParent();
+
+ // Get status of all connections
+ int nItemCount = m_ListCtrl.GetItemCount();
+
+ if (nItemCount == 0)
+ {
+ pParent->SetOutputButtonState(CONNECTION_NONE);
+ return;
+ }
+
+ for (int nItem = 0; nItem < nItemCount; nItem++)
+ {
+ COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
+ if (!pOutputConn->m_bIsValid)
+ {
+ pParent->SetOutputButtonState(CONNECTION_BAD);
+ return;
+ }
+ }
+ pParent->SetOutputButtonState(CONNECTION_GOOD);
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose: Return true if all connections entries are valid for the given
+// output connection. Return false otherwise
+//------------------------------------------------------------------------------
+bool COP_Output::ValidateConnections(COutputConnection *pOutputConn, bool bVisibilityCheck)
+{
+ int nCount = pOutputConn->m_pConnList->Count();
+ for (int i = 0; i < nCount; i++)
+ {
+ CEntityConnection *pConnection = pOutputConn->m_pConnList->Element(i);
+ if (pConnection != NULL)
+ {
+ // Check validity of output for the list of entities
+ if (!CEntityConnection::ValidateOutput(pOutputConn->m_pEntityList,pConnection->GetOutputName()))
+ {
+ return false;
+ }
+
+ // Check validity of target entity (is it in the map?)
+ if (!CEntityConnection::ValidateTarget(m_pMapEntityList, bVisibilityCheck, pConnection->GetTargetName()))
+ {
+ return false;
+ }
+
+ // Check validity of input
+ if (!CEntityConnection::ValidateInput(pConnection->GetTargetName(), pConnection->GetInputName(), bVisibilityCheck))
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pEntity -
+// bFirst -
+//-----------------------------------------------------------------------------
+void COP_Output::AddEntityConnections(CMapEntity *pEntity, bool bFirst)
+{
+ m_ListCtrl.SetRedraw(FALSE);
+
+ //
+ // The first entity simply adds its connections to the list.
+ //
+ int nConnCount = pEntity->Connections_GetCount();
+ for (int i = 0; i < nConnCount; i++)
+ {
+ CEntityConnection *pConnection = pEntity->Connections_Get(i);
+ if (pConnection != NULL)
+ {
+ // First check if the connection already exists, if so just add to it
+ bool bFound = false;
+ int nItemCount = m_ListCtrl.GetItemCount();
+
+ if (nItemCount > 0)
+ {
+ for (int nItem = nItemCount - 1; nItem >= 0; nItem--)
+ {
+ COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
+ CEntityConnectionList *pConnList = pOutputConn->m_pConnList;
+ CEntityConnection *pTestConn = pConnList->Element(0);
+ if (pTestConn->CompareConnection(pConnection))
+ {
+ // Don't consolidate duplicate connections in the same entity
+ // Show them twice so the user will see
+ if ( pOutputConn->m_pEntityList->Find(pEntity) == -1)
+ {
+ pConnList->AddToTail(pConnection);
+ pOutputConn->m_pEntityList->AddToTail(pEntity);
+ bFound = true;
+ break;
+ }
+
+ }
+ }
+ }
+
+ if (!bFound)
+ {
+ m_ListCtrl.SetItemCount(nItemCount + 1);
+
+ m_ListCtrl.InsertItem(LVIF_IMAGE, nItemCount, "", 0, 0, ICON_CONN_GOOD, 0);
+
+ m_ListCtrl.SetItemText(nItemCount, OUTPUT_NAME_COLUMN, pConnection->GetOutputName());
+ m_ListCtrl.SetItemText(nItemCount, TARGET_NAME_COLUMN, pConnection->GetTargetName());
+ m_ListCtrl.SetItemText(nItemCount, INPUT_NAME_COLUMN, pConnection->GetInputName());
+
+ // Build the string for the delay.
+ float fDelay = pConnection->GetDelay();
+ char szTemp[MAX_PATH];
+ sprintf(szTemp, "%.2f", fDelay);
+ m_ListCtrl.SetItemText(nItemCount, DELAY_COLUMN, szTemp);
+
+ // Fire once
+ m_ListCtrl.SetItemText(nItemCount, ONLY_ONCE_COLUMN, (pConnection->GetTimesToFire() == EVENT_FIRE_ALWAYS) ? "No" : "Yes");
+ m_ListCtrl.SetItemText(nItemCount, PARAMETER_COLUMN, pConnection->GetParam());
+
+
+ // Set list ctrl data
+ COutputConnection* pOutputConn = new COutputConnection;
+ pOutputConn->m_pConnList = new CEntityConnectionList;
+ pOutputConn->m_pEntityList = new CMapEntityList;
+ pOutputConn->m_pConnList->AddToTail(pConnection);
+ pOutputConn->m_pEntityList->AddToTail(pEntity);
+ pOutputConn->m_bOwnedByAll = true;
+ m_ListCtrl.SetItemData(nItemCount, (DWORD)pOutputConn);
+
+ nItemCount++;
+ }
+ }
+ }
+
+ m_ListCtrl.SetRedraw(TRUE);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pDX -
+//-----------------------------------------------------------------------------
+void COP_Output::DoDataExchange(CDataExchange *pDX)
+{
+ CObjectPage::DoDataExchange(pDX);
+
+ //{{AFX_DATA_MAP(COP_Output)
+ DDX_Control(pDX, IDC_LIST, m_ListCtrl);
+ DDX_Text(pDX, IDC_EDIT_CONN_DELAY, m_fDelay);
+ DDX_CBString(pDX, IDC_EDIT_CONN_OUTPUT, m_strOutput);
+ DDX_CBString(pDX, IDC_EDIT_CONN_TARGET, m_strTarget);
+ DDX_CBString(pDX, IDC_EDIT_CONN_INPUT, m_strInput);
+ DDX_CBString(pDX, IDC_EDIT_CONN_PARAM, m_strParam);
+ DDX_Check(pDX, IDC_EDIT_CONN_FIRE_ONCE, m_bFireOnce);
+ DDX_Control(pDX, IDC_SHOWHIDDENTARGETS, m_ctlShowHiddenTargetsAsBroken);
+ DDX_Control(pDX, IDC_ADD, m_AddControl);
+ DDX_Control(pDX, IDC_PASTE, m_PasteControl);
+ DDX_Control(pDX, IDC_DELETE, m_DeleteControl);
+
+ //}}AFX_DATA_MAP
+}
+
+
+bool COP_Output::ShouldShowHiddenTargets()
+{
+ return (Options.general.bShowHiddenTargetsAsBroken == TRUE);
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose: Enables or Disables all edit controls
+// Input : bValue -
+//------------------------------------------------------------------------------
+void COP_Output::EnableEditControls(bool bValue)
+{
+ m_ComboOutput.EnableWindow(bValue);
+ EnableTarget(bValue);
+ m_ComboInput.EnableWindow(bValue);
+
+ CButton *pButton = (CButton *)GetDlgItem(IDC_EDIT_CONN_FIRE_ONCE);
+ pButton->EnableWindow(bValue);
+
+ CEdit *pDelayEdit = (CEdit *)GetDlgItem(IDC_EDIT_CONN_DELAY);
+ pDelayEdit->EnableWindow(bValue);
+
+ CComboBox *pParamCombo = (CComboBox *)GetDlgItem(IDC_EDIT_CONN_PARAM);
+ pParamCombo->EnableWindow(bValue);
+ GetDlgItem(IDC_PICK_ENTITY_PARAM)->EnableWindow( bValue );
+
+ // Clear any values
+ if (!bValue)
+ {
+ m_ComboTarget.ForceEditControlText( "" );
+ m_ComboInput.SetWindowText("");
+ m_ComboOutput.SetWindowText("");
+ pParamCombo->SetCurSel(0);
+ pDelayEdit->SetWindowText("0.0");
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pMapEntityList -
+//-----------------------------------------------------------------------------
+void COP_Output::SetMapEntityList(const CMapEntityList *pMapEntityList)
+{
+ m_pMapEntityList = pMapEntityList;
+ FillTargetList();
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose: Updates data displayed in edit controls
+//------------------------------------------------------------------------------
+void COP_Output::UpdateEditControls(void)
+{
+ //
+ // Build a list of connections to edit.
+ //
+ m_EditList.RemoveAll();
+
+ m_AddControl.EnableWindow( ( m_bCanEdit ? TRUE : FALSE ) );
+ m_PasteControl.EnableWindow( ( m_bCanEdit ? TRUE : FALSE ) );
+ m_DeleteControl.EnableWindow( ( m_bCanEdit ? TRUE : FALSE ) );
+
+ // If nothing is selected, disable edit controls
+ if (!m_ListCtrl.IsWindowEnabled() || m_ListCtrl.GetSelectedCount() == 0)
+ {
+ EnableEditControls(false);
+ return;
+ }
+
+ for (int nItem = 0; nItem < m_ListCtrl.GetItemCount(); nItem++)
+ {
+
+ if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
+ {
+ COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
+ m_EditList.AddVectorToTail(*pOutputConn->m_pConnList);
+ }
+ }
+
+ if (m_EditList.Count() > 0)
+ {
+ SetConnection(&m_EditList);
+
+ FillOutputList();
+ FillInputList();
+
+ // We must ignore the text changed event here or else it'll set all selected outputs to the same value.
+ m_bIgnoreTextChanged = true;
+ m_ComboTarget.SelectItem(m_strTarget);
+ m_bIgnoreTextChanged = false;
+
+ m_ComboInput.SetWindowText(m_strInput);
+ m_ComboOutput.SetWindowText(m_strOutput);
+ m_CheckBoxFireOnce.SetCheck(m_bFireOnce);
+
+ CEdit *pDelayEdit = ( CEdit* )GetDlgItem( IDC_EDIT_CONN_DELAY );
+ char szTemp[MAX_PATH];
+ sprintf(szTemp, "%.2f", m_fDelay);
+ pDelayEdit->SetWindowText(szTemp);
+
+ CComboBox* pParamEdit = ( CComboBox* )GetDlgItem( IDC_EDIT_CONN_PARAM );
+ pParamEdit->SetWindowText(m_strParam);
+
+ FilterInputList();
+
+ //
+ // Update the UI state based on our current data.
+ //
+ char szBuf[MAX_IO_NAME_LEN];
+
+ CClassOutput *pOutput = GetOutput(szBuf, sizeof(szBuf));
+ UpdateCombosForSelectedOutput(pOutput);
+
+ CClassInput *pInput = GetInput(szBuf, sizeof(szBuf));
+ UpdateCombosForSelectedInput(pInput);
+
+ //CMapEntityList *pTarget = GetTarget(szBuf, sizeof(szBuf));
+ //UpdateCombosForSelectedTarget(pTarget);
+ }
+
+ if ( m_bCanEdit == false )
+ {
+ EnableEditControls( false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds a connection to all entities being edited.
+//-----------------------------------------------------------------------------
+void COP_Output::OnAdd(void)
+{
+ FOR_EACH_OBJ( m_EntityList, pos)
+ {
+ CMapEntity *pEntity = m_EntityList.Element(pos);
+ if (pEntity != NULL)
+ {
+ CEntityConnection *pConnection = new CEntityConnection;
+ pEntity->Connections_Add(pConnection);
+ }
+ }
+
+ UpdateConnectionList();
+
+ // Set selection to new item, and move the focus to the output combo
+ // so they can just start editing.
+ int nCount = m_ListCtrl.GetItemCount();
+ SetSelectedItem(nCount - 1);
+ m_ListCtrl.EnsureVisible(nCount - 1, FALSE);
+ GetDlgItem(IDC_EDIT_CONN_OUTPUT)->SetFocus();
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose: Clear copy buffer
+//------------------------------------------------------------------------------
+void COP_Output::EmptyCopyBuffer(void)
+{
+ // Delete any old connections
+ int nConnCount = m_pConnectionBuffer->Count();
+ for (int i = 0; i < nConnCount; i++)
+ {
+ CEntityConnection *pConnection = m_pConnectionBuffer->Element(i);
+ if (pConnection != NULL)
+ {
+ delete pConnection;
+ }
+ }
+ m_pConnectionBuffer->RemoveAll();
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Copies list of selected connections into copy buffer
+//-----------------------------------------------------------------------------
+void COP_Output::OnCopy(void)
+{
+ EmptyCopyBuffer();
+
+ if (m_ListCtrl.GetSelectedCount() != 0)
+ {
+ int nCount = m_ListCtrl.GetItemCount();
+ if (nCount > 0)
+ {
+ for (int nItem = nCount - 1; nItem >= 0; nItem--)
+ {
+ if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
+ {
+ //
+ // Each item in the list control is a list of identical connections that are contained
+ // in multiple entities. Add each selected connection to the selected entities.
+ //
+ COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
+ CEntityConnectionList *pConnList = pOutputConn->m_pConnList;
+ if (pConnList != NULL)
+ {
+ CEntityConnection *pConnection = pConnList->Element(0);
+ if (pConnection)
+ {
+ CEntityConnection *pNewConnection = new CEntityConnection;
+ *pNewConnection = *pConnection;
+ m_pConnectionBuffer->AddToTail(pNewConnection);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds a connection to all entities being edited.
+//-----------------------------------------------------------------------------
+void COP_Output::OnPaste(void)
+{
+ // Early out
+ if (!m_pConnectionBuffer->Count())
+ {
+ return;
+ }
+
+ CUtlVector<CEntityConnection *> NewConnections;
+
+ // Add connections from copy buffer to all selected entities
+ FOR_EACH_OBJ( m_EntityList, pos )
+ {
+ CMapEntity *pEntity = m_EntityList.Element(pos);
+ if (pEntity != NULL)
+ {
+ int nConnCount = m_pConnectionBuffer->Count();
+ for (int i = 0; i < nConnCount; i++)
+ {
+ CEntityConnection *pConnection = m_pConnectionBuffer->Element(i);
+ if (pConnection != NULL)
+ {
+ CEntityConnection *pNewConnection = new CEntityConnection;
+ *pNewConnection = *pConnection;
+ pEntity->Connections_Add(pNewConnection);
+
+ NewConnections.AddToTail(pNewConnection);
+ }
+ }
+ }
+ }
+ UpdateConnectionList();
+ SortListByColumn(m_nSortColumn, m_eSortDirection[m_nSortColumn]);
+ SetSelectedConnections(NewConnections);
+ GetDlgItem(IDC_EDIT_CONN_OUTPUT)->SetFocus();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COP_Output::OnPickEntity(void)
+{
+ CButton *pButton = (CButton *)GetDlgItem(IDC_PICK_ENTITY);
+ Assert(pButton != NULL);
+
+ if (pButton != NULL)
+ {
+ if (pButton->GetCheck())
+ {
+ //
+ // Activate the entity picker tool.
+ //
+ m_bPickingEntities = true;
+ m_PickEntityTarget.AttachDlgItem( IDC_EDIT_CONN_TARGET );
+ CToolPickEntity *pTool = (CToolPickEntity *)ToolManager()->GetToolForID(TOOL_PICK_ENTITY);
+ pTool->Attach(&m_PickEntityTarget);
+ ToolManager()->SetTool(TOOL_PICK_ENTITY);
+ GetDlgItem(IDC_PICK_ENTITY_PARAM)->EnableWindow( false );
+ }
+ else
+ {
+ StopPicking();
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COP_Output::OnPickEntityParam(void)
+{
+ CButton *pButton = (CButton *)GetDlgItem(IDC_PICK_ENTITY_PARAM);
+ Assert(pButton != NULL);
+
+ if (pButton != NULL)
+ {
+ if (pButton->GetCheck())
+ {
+ //
+ // Activate the entity picker tool.
+ //
+ m_bPickingEntities = true;
+ m_PickEntityTarget.AttachDlgItem( IDC_EDIT_CONN_PARAM );
+ CToolPickEntity *pTool = (CToolPickEntity *)ToolManager()->GetToolForID(TOOL_PICK_ENTITY);
+ pTool->Attach(&m_PickEntityTarget);
+ ToolManager()->SetTool(TOOL_PICK_ENTITY);
+ GetDlgItem(IDC_PICK_ENTITY)->EnableWindow( false );
+ }
+ else
+ {
+ StopPicking();
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Deletes all selected items from the connection list, and removes the
+// corresponding connections from the list of entities being edited.
+//-----------------------------------------------------------------------------
+void COP_Output::OnDelete(void)
+{
+ if (m_ListCtrl.GetSelectedCount() != 0)
+ {
+ int nCount = m_ListCtrl.GetItemCount();
+ int nLastItem = 0;
+ if (nCount > 0)
+ {
+ for (int nItem = nCount - 1; nItem >= 0; nItem--)
+ {
+ if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
+ {
+ //
+ // Each item in the list control is a list of identical connections that are contained
+ // in multiple entities. Since we don't store the containing entity along with the connection,
+ // just try to remove all the connections in the list from all the selected entities.
+ //
+ COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
+ CEntityConnectionList *pConnList = pOutputConn->m_pConnList;
+ m_ListCtrl.DeleteItem(nItem);
+
+ if (pConnList != NULL)
+ {
+ int nConnCount = pConnList->Count();
+ for (int nConn = 0; nConn < nConnCount; nConn++)
+ {
+ CEntityConnection *pConnection = pConnList->Element(nConn);
+ if (pConnection != NULL)
+ {
+ //
+ // Remove the connection from all entities being edited.
+ //
+ FOR_EACH_OBJ( m_EntityList, pos )
+ {
+ CMapEntity *pEntity = m_EntityList.Element(pos);
+ if (pEntity != NULL)
+ {
+ pEntity->Connections_Remove(pConnection);
+ }
+ }
+
+ //
+ // Remove the connection from the upstream list of all entities it targets.
+ //
+ CMapEntityList *pTargetList = pConnection->GetTargetEntityList();
+ if ( pTargetList )
+ {
+ FOR_EACH_OBJ( *pTargetList, pos2 )
+ {
+ CMapEntity *pEntity = pTargetList->Element( pos2 );
+ pEntity->Upstream_Remove( pConnection );
+ }
+ }
+ }
+
+ delete pConnection;
+ }
+
+ delete pConnList;
+ }
+ // Keep track of last item so can set selection focus
+ nLastItem = nItem;
+ }
+ }
+ }
+
+ // Set selection focus as point of deletion or on last item
+ int nNumItems = m_ListCtrl.GetItemCount()-1;
+ if (nLastItem > nNumItems)
+ {
+ nLastItem = nNumItems;
+ }
+ SetSelectedItem(nLastItem);
+ UpdateValidityButton();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose : Take the user to the output page of the selected entity that
+// targets me.
+// Input :
+// Output :
+//------------------------------------------------------------------------------
+void COP_Output::OnMark(void)
+{
+ int nCount = m_ListCtrl.GetItemCount();
+ CMapDoc* pDoc = CMapDoc::GetActiveMapDoc();
+
+ CEntityConnection *pConnection = NULL;
+
+ if (nCount > 0 && pDoc)
+ {
+ CMapObjectList Select;
+
+ for (int nItem = nCount - 1; nItem >= 0; nItem--)
+ {
+ if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
+ {
+ COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
+ pConnection = pOutputConn->m_pConnList->Element(0);
+
+ CMapDoc *pDocActive = CMapDoc::GetActiveMapDoc();
+ if ( pDocActive != NULL)
+ {
+ CMapEntityList Found;
+ pDocActive->FindEntitiesByName(Found, m_ListCtrl.GetItemText(nItem, TARGET_NAME_COLUMN), false);
+
+ FOR_EACH_OBJ( Found, pos )
+ {
+ CMapEntity *pEntity = Found.Element(pos);
+ Select.AddToTail(pEntity);
+ }
+ }
+ }
+ }
+ if (Select.Count()>0)
+ {
+ pDoc->SelectObjectList(&Select);
+
+ // (a bit squirly way of doing this)
+ if ( Select.Count()==1 )
+ GetMainWnd()->pObjectProperties->SetPageToInput(pConnection);
+
+ pDoc->Center2DViewsOnSelection();
+ }
+ else
+ {
+ MessageBox("No entities were found with that targetname.", "No entities found", MB_ICONINFORMATION | MB_OK);
+ return;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets up the list view columns, initial sort column.
+//-----------------------------------------------------------------------------
+BOOL COP_Output::OnInitDialog(void)
+{
+ CObjectPage::OnInitDialog();
+
+ m_ComboOutput.SubclassDlgItem(IDC_EDIT_CONN_OUTPUT, this);
+ m_ComboInput.SubclassDlgItem(IDC_EDIT_CONN_INPUT, this);
+ m_ComboTarget.SubclassDlgItem(IDC_EDIT_CONN_TARGET, this);
+ m_CheckBoxFireOnce.SubclassDlgItem(IDC_EDIT_CONN_FIRE_ONCE, this);
+
+ m_ListCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP);
+
+ m_ListCtrl.InsertColumn(ICON_COLUMN, "", LVCFMT_CENTER, 20);
+ m_ListCtrl.InsertColumn(OUTPUT_NAME_COLUMN, "My Output", LVCFMT_LEFT, 70);
+ m_ListCtrl.InsertColumn(TARGET_NAME_COLUMN, "Target Entity", LVCFMT_LEFT, 70);
+ m_ListCtrl.InsertColumn(INPUT_NAME_COLUMN, "Target Input", LVCFMT_LEFT, 70);
+ m_ListCtrl.InsertColumn(DELAY_COLUMN, "Delay", LVCFMT_LEFT, 70);
+ m_ListCtrl.InsertColumn(ONLY_ONCE_COLUMN, "Only Once", LVCFMT_LEFT, 70);
+ m_ListCtrl.InsertColumn(PARAMETER_COLUMN, "Parameter", LVCFMT_LEFT, 70);
+
+ UpdateConnectionList();
+
+ SetSortColumn(m_nSortColumn, m_eSortDirection[m_nSortColumn]);
+
+ // Force an update of the column header text so that the sort indicator is shown.
+ UpdateColumnHeaderText(m_nSortColumn, true, m_eSortDirection[m_nSortColumn]);
+
+ ResizeColumns();
+
+ m_strLastParam.Empty();
+
+ // Select the first item in the combo box
+ SetSelectedItem(0);
+
+ // Create image list. Is deleted automatically when listctrl is deleted
+ if (!m_pImageList)
+ {
+ CWinApp *pApp = AfxGetApp();
+ m_pImageList = new CImageList();
+ Assert(m_pImageList != NULL); // serious allocation failure checking
+ m_pImageList->Create(16, 16, TRUE, 1, 0);
+ m_pImageList->Add(pApp->LoadIcon( IDI_OUTPUTBAD ));
+ m_pImageList->Add(pApp->LoadIcon( IDI_OUTPUT ));
+ m_pImageList->Add(pApp->LoadIcon( IDI_OUTPUTBAD_GREY ));
+ m_pImageList->Add(pApp->LoadIcon( IDI_OUTPUT_GREY ));
+
+ }
+ m_ListCtrl.SetImageList(m_pImageList, LVSIL_SMALL );
+
+ // Apply the eyedropper image to the picker buttons.
+ CButton *pButton = (CButton *)GetDlgItem(IDC_PICK_ENTITY);
+ if (pButton)
+ {
+ CWinApp *pApp = AfxGetApp();
+ HICON hIcon = pApp->LoadIcon(IDI_EYEDROPPER);
+ pButton->SetIcon(hIcon);
+ }
+
+ pButton = (CButton *)GetDlgItem(IDC_PICK_ENTITY_PARAM);
+ if (pButton)
+ {
+ CWinApp *pApp = AfxGetApp();
+ HICON hIcon = pApp->LoadIcon(IDI_EYEDROPPER);
+ pButton->SetIcon(hIcon);
+ }
+
+ CAnchorDef anchorDefs[] =
+ {
+ CAnchorDef( IDC_LIST, k_eSimpleAnchorAllSides ),
+ CAnchorDef( IDC_OUTPUTS_STATIC_PANEL, k_eAnchorLeft, k_eAnchorBottom, k_eAnchorRight, k_eAnchorBottom ),
+ CAnchorDef( IDC_OUTPUT_LABEL, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_TARGETS_LABEL, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_VIA_INPUT_LABEL, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_PARAMETER_LABEL, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_DELAY_LABEL, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_EDIT_CONN_DELAY, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_EDIT_CONN_FIRE_ONCE, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_EDIT_CONN_PARAM, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_EDIT_CONN_INPUT, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_EDIT_CONN_TARGET, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_EDIT_CONN_OUTPUT, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_PICK_ENTITY, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_PICK_ENTITY_PARAM, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_MARK, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_ADD, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_COPY, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_PASTE, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_DELETE, k_eSimpleAnchorBottomSide ),
+ CAnchorDef( IDC_SHOWHIDDENTARGETS, k_eSimpleAnchorBottomRight )
+ };
+ m_AnchorMgr.Init( GetSafeHwnd(), anchorDefs, ARRAYSIZE( anchorDefs ) );
+
+ // Set the last state this was at.
+ m_ctlShowHiddenTargetsAsBroken.SetCheck( ShouldShowHiddenTargets() );
+ return(TRUE);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : wParam -
+// lParam -
+// pResult -
+// Output : Returns TRUE on success, FALSE on failure.
+//-----------------------------------------------------------------------------
+BOOL COP_Output::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT *pResult)
+{
+ NMHDR *pnmh = (NMHDR *)lParam;
+
+ if (pnmh->idFrom == IDC_LIST)
+ {
+ switch (pnmh->code)
+ {
+ case LVN_COLUMNCLICK:
+ {
+ NMLISTVIEW *pnmv = (NMLISTVIEW *)lParam;
+ if (pnmv->iSubItem < OUTPUT_LIST_NUM_COLUMNS)
+ {
+ SortDirection_t eSortDirection = m_eSortDirection[pnmv->iSubItem];
+
+ //
+ // If they clicked on the current sort column, reverse the sort direction.
+ //
+ if (pnmv->iSubItem == m_nSortColumn)
+ {
+ if (m_eSortDirection[m_nSortColumn] == Sort_Ascending)
+ {
+ eSortDirection = Sort_Descending;
+ }
+ else
+ {
+ eSortDirection = Sort_Ascending;
+ }
+ }
+
+ //
+ // Update the sort column and sort the list.
+ //
+ SetSortColumn(pnmv->iSubItem, eSortDirection);
+ }
+
+ return(TRUE);
+ }
+
+ case NM_DBLCLK:
+ {
+ OnMark();
+ return(TRUE);
+ }
+
+ case LVN_ITEMCHANGED:
+ {
+ NMLISTVIEW *pnmv = (NMLISTVIEW *)lParam;
+ if ( ( pnmv->uNewState & LVIS_SELECTED ) != ( pnmv->uOldState & LVIS_SELECTED ) )
+ {
+ // Listbox selection has changed so update edit controls
+ if (!bSkipEditControlRefresh)
+ {
+ UpdateEditControls();
+ }
+ bSkipEditControlRefresh = false;
+
+ // Forget the saved param, because it was for a different I/O connection.
+ m_strLastParam.Empty();
+ }
+
+ return(TRUE);
+ }
+ }
+ }
+
+ return(CObjectPage::OnNotify(wParam, lParam, pResult));
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Empties the contents of the connections list control, freeing the
+// connection list hanging off of each row.
+//-----------------------------------------------------------------------------
+void COP_Output::RemoveAllEntityConnections(void)
+{
+ m_ListCtrl.SetRedraw(FALSE);
+
+ int nCount = m_ListCtrl.GetItemCount();
+ if (nCount > 0)
+ {
+ for (int nItem = nCount - 1; nItem >= 0; nItem--)
+ {
+ COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
+ CEntityConnectionList *pConnList = pOutputConn->m_pConnList;
+ CMapEntityList *pEntityList = pOutputConn->m_pEntityList;
+
+ m_ListCtrl.DeleteItem(nItem);
+
+ delete pOutputConn;
+ delete pConnList;
+ delete pEntityList;
+ }
+ }
+
+ m_ListCtrl.SetRedraw(TRUE);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : Mode -
+// pData -
+//-----------------------------------------------------------------------------
+void COP_Output::UpdateData( int Mode, PVOID pData, bool bCanEdit )
+{
+ __super::UpdateData( Mode, pData, bCanEdit );
+
+ if (!IsWindow(m_hWnd))
+ {
+ return;
+ }
+
+ switch (Mode)
+ {
+ case LoadFirstData:
+ {
+// m_ListCtrl.DeleteAllItems();
+// UpdateConnectionList();
+ break;
+ }
+
+ case LoadData:
+ {
+// m_ListCtrl.DeleteAllItems();
+// UpdateConnectionList();
+// SetSelectedItem(0);
+ break;
+ }
+
+ case LoadFinished:
+ {
+ m_ListCtrl.DeleteAllItems();
+ UpdateConnectionList();
+ SetSelectedItem(0);
+ SortListByColumn(m_nSortColumn, m_eSortDirection[m_nSortColumn]);
+ }
+ }
+
+ UpdateEditControls();
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose: Generates list of map entites that are being edited from the
+// m_pObject list
+//------------------------------------------------------------------------------
+void COP_Output::UpdateEntityList(void)
+{
+ // Clear old entity list
+ m_EntityList.RemoveAll();
+
+ if (m_pObjectList != NULL)
+ {
+ FOR_EACH_OBJ( *m_pObjectList, pos )
+ {
+ CMapClass *pObject = m_pObjectList->Element(pos);
+
+ if ((pObject != NULL) && (pObject->IsMapClass(MAPCLASS_TYPE(CMapEntity))) )
+ {
+ CMapEntity *pEntity = (CMapEntity *)pObject;
+ m_EntityList.AddToTail(pEntity);
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : nColumn -
+// eDirection -
+//-----------------------------------------------------------------------------
+void COP_Output::SetSortColumn(int nColumn, SortDirection_t eDirection)
+{
+ Assert(nColumn < OUTPUT_LIST_NUM_COLUMNS);
+
+ //
+ // If the sort column changed, update the old sort column header text.
+ //
+ if (m_nSortColumn != nColumn)
+ {
+ UpdateColumnHeaderText(m_nSortColumn, false, eDirection);
+ }
+
+ //
+ // If the sort column or direction changed, update the new sort column header text.
+ //
+ if ((m_nSortColumn != nColumn) || (m_eSortDirection[m_nSortColumn] != eDirection))
+ {
+ UpdateColumnHeaderText(nColumn, true, eDirection);
+ }
+
+ m_nSortColumn = nColumn;
+ m_eSortDirection[m_nSortColumn] = eDirection;
+
+ SortListByColumn(m_nSortColumn, m_eSortDirection[m_nSortColumn]);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sorts the outputs list by column.
+// Input : nColumn - Index of column by which to sort.
+//-----------------------------------------------------------------------------
+void COP_Output::SortListByColumn(int nColumn, SortDirection_t eDirection)
+{
+ PFNLVCOMPARE pfnSort = NULL;
+
+ switch (nColumn)
+ {
+ case ONLY_ONCE_COLUMN:
+ {
+ //No Sort
+ break;
+ }
+
+ case PARAMETER_COLUMN:
+ {
+ //No Sort
+ break;
+ }
+
+ case OUTPUT_NAME_COLUMN:
+ {
+ pfnSort = (PFNLVCOMPARE)ListCompareOutputNames;
+ break;
+ }
+
+ case TARGET_NAME_COLUMN:
+ {
+ pfnSort = (PFNLVCOMPARE)ListCompareTargetNames;
+ break;
+ }
+
+ case INPUT_NAME_COLUMN:
+ {
+ pfnSort = (PFNLVCOMPARE)ListCompareInputNames;
+ break;
+ }
+
+ case DELAY_COLUMN:
+ {
+ pfnSort = (PFNLVCOMPARE)ListCompareDelays;
+ break;
+ }
+
+ default:
+ {
+ Assert(FALSE);
+ break;
+ }
+ }
+
+ if (pfnSort != NULL)
+ {
+ m_ListCtrl.SortItems(pfnSort, (DWORD)eDirection);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COP_Output::ResizeColumns(void)
+{
+ if (m_ListCtrl.GetItemCount() > 0)
+ {
+ m_ListCtrl.SetColumnWidth(OUTPUT_NAME_COLUMN, LVSCW_AUTOSIZE);
+ m_ListCtrl.SetColumnWidth(TARGET_NAME_COLUMN, LVSCW_AUTOSIZE);
+ m_ListCtrl.SetColumnWidth(INPUT_NAME_COLUMN, LVSCW_AUTOSIZE);
+ m_ListCtrl.SetColumnWidth(DELAY_COLUMN, LVSCW_AUTOSIZE_USEHEADER);
+ m_ListCtrl.SetColumnWidth(ONLY_ONCE_COLUMN, LVSCW_AUTOSIZE_USEHEADER);
+ m_ListCtrl.SetColumnWidth(PARAMETER_COLUMN, LVSCW_AUTOSIZE);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COP_Output::UpdateConnectionList(void)
+{
+ // Get list of all entities in the world
+ CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
+ Assert(pDoc != NULL);
+ if (!pDoc)
+ return;
+
+ CMapWorld *pWorld = pDoc->GetMapWorld();
+ Assert(pWorld != NULL); // dvs: I've seen pWorld be NULL on app shutdown, not sure why we ended up here though
+ if (!pWorld)
+ return;
+
+ SetMapEntityList(pWorld->EntityList_GetList());
+
+ UpdateEntityList();
+ RemoveAllEntityConnections();
+
+ bool bFirst = true;
+
+ FOR_EACH_OBJ( m_EntityList, pos )
+ {
+ CMapEntity *pEntity = m_EntityList.Element(pos);
+ if (pEntity != NULL)
+ {
+ AddEntityConnections(pEntity, bFirst);
+ bFirst = false;
+ }
+ }
+
+ // Update validity flag on all items
+ for (int nItem = 0; nItem < m_ListCtrl.GetItemCount(); nItem++)
+ {
+ UpdateItemValidity(nItem);
+ }
+ UpdateValidityButton();
+
+ ResizeColumns();
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose: Set the selected item in the listbox by index.
+// Input : nSelectItem -
+//------------------------------------------------------------------------------
+void COP_Output::SetSelectedItem(int nSelectItem)
+{
+ m_ListCtrl.SetRedraw(FALSE);
+
+ // Set selected item to be active and all others to false
+ int nItemCount = m_ListCtrl.GetItemCount();
+ for (int nItem = 0; nItem < nItemCount; nItem++)
+ {
+ if (nItem == nSelectItem)
+ {
+ m_ListCtrl.SetItemState(nItem, (unsigned int)LVIS_SELECTED, (unsigned int)LVIS_SELECTED);
+ }
+ else
+ {
+ m_ListCtrl.SetItemState(nItem, (unsigned int)~LVIS_SELECTED, (unsigned int)LVIS_SELECTED);
+ }
+ }
+
+ m_ListCtrl.SetRedraw(TRUE);
+
+ // Selected item has changed so update edit controls
+ UpdateEditControls();
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose: Set the selected item in the listbox
+// Input : pConnection
+//------------------------------------------------------------------------------
+void COP_Output::SetSelectedConnection(CEntityConnection *pConnection)
+{
+ m_ListCtrl.SetRedraw(FALSE);
+
+ // Set selected item to be active and all others to false
+ int nItemCount = m_ListCtrl.GetItemCount();
+ for (int nItem = 0; nItem < nItemCount; nItem++)
+ {
+ COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
+ CEntityConnectionList *pTestList = pOutputConn->m_pConnList;
+
+ if (pTestList->Element(0) == pConnection)
+ {
+ m_ListCtrl.SetItemState(nItem,LVIS_SELECTED,LVIS_SELECTED);
+ }
+ else
+ {
+ m_ListCtrl.SetItemState(nItem, (unsigned int)~LVIS_SELECTED, (unsigned int)LVIS_SELECTED);
+ }
+ }
+
+ m_ListCtrl.SetRedraw(TRUE);
+
+ // Selected item has changed so update edit controls
+ UpdateEditControls();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Selects the list box entries that correspond to the connections in
+// the given list.
+//-----------------------------------------------------------------------------
+void COP_Output::SetSelectedConnections(CEntityConnectionList &List)
+{
+ m_ListCtrl.SetRedraw(FALSE);
+
+ int nConnCount = List.Count();
+
+ int nItemCount = m_ListCtrl.GetItemCount();
+ for (int nItem = 0; nItem < nItemCount; nItem++)
+ {
+ COutputConnection *pOutputConn = (COutputConnection *)m_ListCtrl.GetItemData(nItem);
+ CEntityConnectionList *pConnList = pOutputConn->m_pConnList;
+
+ // See if this row's list holds any of the connections in the given list.
+ bool bFound = false;
+ for (int nConn = 0; nConn < nConnCount; nConn++)
+ {
+ CEntityConnection *pConn = List.Element(nConn);
+ if (pConnList->Find(pConn) != -1)
+ {
+ bFound = true;
+ break;
+ }
+ }
+
+ m_ListCtrl.SetItemState(nItem, bFound ? LVIS_SELECTED : ~LVIS_SELECTED, LVIS_SELECTED);
+ }
+
+ m_ListCtrl.SetRedraw(TRUE);
+
+ UpdateEditControls();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds or removes the little 'V' or '^' sort indicator as appropriate.
+// Input : nColumn - Index of column to update.
+// bSortColumn - true if this column is the sort column, false if not.
+// eDirection - Direction of sort, Sort_Ascending or Sort_Descending.
+//-----------------------------------------------------------------------------
+void COP_Output::UpdateColumnHeaderText(int nColumn, bool bIsSortColumn, SortDirection_t eDirection)
+{
+ char szHeaderText[MAX_PATH];
+
+ LVCOLUMN Column;
+ memset(&Column, 0, sizeof(Column));
+ Column.mask = LVCF_TEXT;
+ Column.pszText = szHeaderText;
+ Column.cchTextMax = sizeof(szHeaderText);
+ m_ListCtrl.GetColumn(nColumn, &Column);
+
+ int nMarker = 0;
+
+ if (szHeaderText[0] != '\0')
+ {
+ nMarker = strlen(szHeaderText) - 1;
+ char chMarker = szHeaderText[nMarker];
+
+ if ((chMarker == '>') || (chMarker == '<'))
+ {
+ nMarker -= 2;
+ }
+ else
+ {
+ nMarker++;
+ }
+ }
+
+ if (bIsSortColumn)
+ {
+ if (nMarker != 0)
+ {
+ szHeaderText[nMarker++] = ' ';
+ szHeaderText[nMarker++] = ' ';
+ }
+
+ szHeaderText[nMarker++] = (eDirection == Sort_Ascending) ? '>' : '<';
+ }
+
+ szHeaderText[nMarker] = '\0';
+
+ m_ListCtrl.SetColumn(nColumn, &Column);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when our window is being destroyed.
+//-----------------------------------------------------------------------------
+void COP_Output::OnDestroy(void)
+{
+ m_ListCtrl.EnableWindow(false);
+ RemoveAllEntityConnections();
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose:
+//------------------------------------------------------------------------------
+void COP_Output::UpdateEditedFireOnce(void)
+{
+ // Get new delay
+ CButton *pButton = ( CButton* )GetDlgItem( IDC_EDIT_CONN_FIRE_ONCE );
+
+ if (pButton->IsWindowEnabled())
+ {
+ int nChecked = (pButton->GetState()&0x0003); // Checked state
+
+ // Update the connections
+ int nConnCount = m_EditList.Count();
+ for (int nConn = 0; nConn < nConnCount; nConn++)
+ {
+ CEntityConnection *pConnection = m_EditList.Element(nConn);
+ if (pConnection != NULL)
+ {
+ pConnection->SetTimesToFire(nChecked?1:EVENT_FIRE_ALWAYS);
+ }
+ }
+
+ // Update the list box
+ for (int nItem = 0; nItem < m_ListCtrl.GetItemCount(); nItem++)
+ {
+ if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
+ {
+ m_ListCtrl.SetItemText(nItem, ONLY_ONCE_COLUMN, nChecked ? "Yes" : "No");
+ }
+ }
+ ResizeColumns();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose:
+//------------------------------------------------------------------------------
+void COP_Output::UpdateEditedDelays(void)
+{
+ // Get new delay
+ CEdit *pDelayEdit = ( CEdit* )GetDlgItem( IDC_EDIT_CONN_DELAY );
+
+ if (pDelayEdit->IsWindowEnabled())
+ {
+ char strDelay[MAX_IO_NAME_LEN];
+ pDelayEdit->GetWindowText(strDelay, sizeof(strDelay));
+ float flDelay = atof(strDelay);
+
+ // Update the connections
+ int nConnCount = m_EditList.Count();
+ for (int nConn = 0; nConn < nConnCount; nConn++)
+ {
+ CEntityConnection *pConnection = m_EditList.Element(nConn);
+ if (pConnection != NULL)
+ {
+ pConnection->SetDelay(flDelay);
+ }
+ }
+
+ // Update the list box
+ for (int nItem = 0; nItem < m_ListCtrl.GetItemCount(); nItem++)
+ {
+ if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
+ {
+ m_ListCtrl.SetItemText(nItem, DELAY_COLUMN, strDelay);
+ }
+ }
+ ResizeColumns();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose: Parameters have changed. Update connections and listbox
+//------------------------------------------------------------------------------
+void COP_Output::UpdateEditedParams(void)
+{
+ CComboBox *pParamEdit = ( CComboBox* )GetDlgItem( IDC_EDIT_CONN_PARAM );
+
+ if (pParamEdit->IsWindowEnabled())
+ {
+ char strParam[MAX_IO_NAME_LEN];
+ pParamEdit->GetWindowText(strParam, sizeof(strParam));
+ if (!strcmp(strParam, PARAM_STRING_NONE))
+ {
+ strParam[0] = '\0';
+ }
+
+ // Update the connections
+ int nConnCount = m_EditList.Count();
+ for (int nConn = 0; nConn < nConnCount; nConn++)
+ {
+ CEntityConnection *pConnection = m_EditList.Element(nConn);
+ if (pConnection != NULL)
+ {
+ pConnection->SetParam(strParam);
+ }
+ }
+
+ // Update the list box
+ for (int nItem = 0; nItem < m_ListCtrl.GetItemCount(); nItem++)
+ {
+ if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
+ {
+ m_ListCtrl.SetItemText(nItem, PARAMETER_COLUMN, strParam);
+ }
+ }
+ ResizeColumns();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose: Inputs have changed. Update connections and listbox
+//------------------------------------------------------------------------------
+void COP_Output::UpdateEditedInputs(void)
+{
+ // Get the new name
+ char strInput[MAX_IO_NAME_LEN];
+ GetInput(strInput, sizeof(strInput));
+
+ // Update the connections
+ int nConnCount = m_EditList.Count();
+ for (int nConn = 0; nConn < nConnCount; nConn++)
+ {
+ CEntityConnection *pConnection = m_EditList.Element(nConn);
+ if (pConnection != NULL)
+ {
+ pConnection->SetInputName(strInput);
+ }
+ }
+
+ // Update the list box
+ for (int nItem = 0; nItem < m_ListCtrl.GetItemCount(); nItem++)
+ {
+ if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
+ {
+ m_ListCtrl.SetItemText(nItem, INPUT_NAME_COLUMN, strInput);
+ UpdateItemValidity(nItem);
+ }
+ }
+ UpdateValidityButton();
+ ResizeColumns();
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose: Outputs have changed. Update connections and listbox
+//------------------------------------------------------------------------------
+void COP_Output::UpdateEditedOutputs()
+{
+ // Get the new name
+ char strOutput[MAX_IO_NAME_LEN];
+ GetOutput(strOutput, sizeof(strOutput));
+
+ // Update the connections
+ int nConnCount = m_EditList.Count();
+ for (int nConn = 0; nConn < nConnCount; nConn++)
+ {
+ CEntityConnection *pConnection = m_EditList.Element(nConn);
+ if (pConnection != NULL)
+ {
+ pConnection->SetOutputName(strOutput);
+ }
+ }
+
+ // Update the list box
+ for (int nItem = 0; nItem < m_ListCtrl.GetItemCount(); nItem++)
+ {
+ if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
+ {
+ m_ListCtrl.SetItemText(nItem, OUTPUT_NAME_COLUMN, strOutput);
+ UpdateItemValidity(nItem);
+ }
+ }
+ UpdateValidityButton();
+ ResizeColumns();
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose: Targets have changed. Update connections and listbox
+//------------------------------------------------------------------------------
+void COP_Output::UpdateEditedTargets(void)
+{
+ // Get the new target name
+ char strTarget[MAX_IO_NAME_LEN];
+ GetTarget(strTarget, sizeof(strTarget));
+
+ // Update the connections
+ int nConnCount = m_EditList.Count();
+ for (int nConn = 0; nConn < nConnCount; nConn++)
+ {
+ CEntityConnection *pConnection = m_EditList.Element(nConn);
+ if (pConnection != NULL)
+ {
+ pConnection->SetTargetName(strTarget);
+ }
+ }
+
+ // Update the list box
+ for (int nItem = 0; nItem < m_ListCtrl.GetItemCount(); nItem++)
+ {
+ if (m_ListCtrl.GetItemState(nItem, LVIS_SELECTED) & LVIS_SELECTED)
+ {
+ m_ListCtrl.SetItemText(nItem, TARGET_NAME_COLUMN, strTarget);
+ UpdateItemValidity(nItem);
+ }
+ }
+ UpdateValidityButton();
+ ResizeColumns();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Enables or diables the target combo box and the eyedropper button.
+//-----------------------------------------------------------------------------
+void COP_Output::EnableTarget(bool bEnable)
+{
+ m_ComboTarget.EnableWindow(bEnable);
+ GetDlgItem(IDC_PICK_ENTITY)->EnableWindow(bEnable);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pConnection -
+//-----------------------------------------------------------------------------
+void COP_Output::SetConnection(CEntityConnectionList *pConnectionList)
+{
+ Assert(pConnectionList != NULL);
+
+ // Fill edit boxes. Disable for multiple connections have incompatible data
+ bool bFirst = true;
+ CButton* pFireEdit = ( CButton* )GetDlgItem( IDC_EDIT_CONN_FIRE_ONCE );
+ CEdit* pDelayEdit = ( CEdit* )GetDlgItem( IDC_EDIT_CONN_DELAY );
+ CComboBox* pParamEdit = ( CComboBox* )GetDlgItem( IDC_EDIT_CONN_PARAM );
+
+ m_ComboOutput.EnableWindow(true);
+ EnableTarget(true);
+ m_ComboInput.EnableWindow(true);
+ pFireEdit->EnableWindow(true);
+ pDelayEdit->EnableWindow(true);
+ pParamEdit->EnableWindow(true);
+ GetDlgItem(IDC_PICK_ENTITY_PARAM)->EnableWindow( false );
+ m_bEntityParamTarget = false;
+
+ int nConnCount = pConnectionList->Count();
+ for (int nConn = 0; nConn < nConnCount; nConn++)
+ {
+ CEntityConnection *pConnection = (CEntityConnection *)pConnectionList->Element(nConn);
+ if (pConnection == NULL)
+ continue;
+
+ // Fill in output name, disable for non-compatible connections
+ if (m_ComboOutput.IsWindowEnabled())
+ {
+ if (bFirst)
+ {
+ m_strOutput = pConnection->GetOutputName();
+ }
+ else if (m_strOutput != pConnection->GetOutputName())
+ {
+ m_strOutput.Empty();
+ m_ComboOutput.EnableWindow(false);
+ }
+ }
+
+ // Fill in target name, disable for non-compatible connections
+ if (m_ComboTarget.IsWindowEnabled())
+ {
+ if (bFirst)
+ {
+ m_strTarget = pConnection->GetTargetName();
+ }
+ else if (m_strTarget != pConnection->GetTargetName())
+ {
+ m_strTarget.Empty();
+ EnableTarget(false);
+ }
+ }
+
+ // Fill in input name, disable for non-compatible connections
+ if (m_ComboInput.IsWindowEnabled())
+ {
+ if (bFirst)
+ {
+ m_strInput = pConnection->GetInputName();
+ }
+ else if (m_strInput != pConnection->GetInputName())
+ {
+ m_strInput.Empty();
+ m_ComboInput.EnableWindow(false);
+ }
+ }
+
+ // Fill in parameters, disable for non-compatible connections
+ if (pParamEdit->IsWindowEnabled())
+ {
+ if (bFirst)
+ {
+ m_strParam = pConnection->GetParam();
+ m_bNoParamEdit = false;
+ }
+ else if (m_strParam != pConnection->GetParam())
+ {
+ m_strParam.Empty();
+ pParamEdit->EnableWindow(false);
+ GetDlgItem(IDC_PICK_ENTITY_PARAM)->EnableWindow( false );
+ m_bNoParamEdit = true;
+ }
+ }
+
+ // Fill in delay, disable for non-compatible connections
+ if (pDelayEdit->IsWindowEnabled())
+ {
+ if (bFirst)
+ {
+ m_fDelay = pConnection->GetDelay();
+ }
+ else if (m_fDelay != pConnection->GetDelay())
+ {
+ m_fDelay = 0;
+ pDelayEdit->EnableWindow(false);
+ }
+ }
+
+ // Set fire once flag, disable for non-compatible connections
+ if (pFireEdit->IsWindowEnabled())
+ {
+ if (bFirst)
+ {
+ m_bFireOnce = (pConnection->GetTimesToFire() == -1) ? false : true;
+ }
+ else if (m_bFireOnce != pConnection->GetTimesToFire())
+ {
+ m_bFireOnce = false;
+ pFireEdit->EnableWindow(false);
+ }
+ }
+
+ bFirst = false;
+ }
+
+ // Put a <none> in param box if no param
+ if (strlen(m_strParam) == 0)
+ {
+ m_strParam = PARAM_STRING_NONE;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds all of an entity's outputs from its class definition to the
+// outputs combo box.
+// Input : pEntity - Entity whose outputs are to be added to the combo box.
+//-----------------------------------------------------------------------------
+void COP_Output::AddEntityOutputs(CMapEntity *pEntity)
+{
+ GDclass *pClass = pEntity->GetClass();
+ if (pClass != NULL)
+ {
+ int nCount = pClass->GetOutputCount();
+ for (int i = 0; i < nCount; i++)
+ {
+ CClassOutput *pOutput = pClass->GetOutput(i);
+ int nIndex = m_ComboOutput.AddString(pOutput->GetName());
+ if (nIndex >= 0)
+ {
+ m_ComboOutput.SetItemDataPtr(nIndex, pOutput);
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COP_Output::FillInputList(void)
+{
+ if (!m_pMapEntityList)
+ {
+ return;
+ }
+
+ //
+ // Add all entity inputs to the inputs combo box.
+ //
+ m_ComboInput.SetRedraw(FALSE);
+ m_ComboInput.ResetContent();
+
+ // CUtlVector<GDclass*> classCache;
+ CUtlRBTree<int,int> classCache;
+ SetDefLessFunc( classCache );
+
+ FOR_EACH_OBJ( *m_pMapEntityList, pos )
+ {
+ CMapEntity *pEntity = m_pMapEntityList->Element(pos);
+ Assert(pEntity != NULL);
+
+ if (pEntity == NULL)
+ continue;
+
+ //
+ // Get the entity's class, which contains the list of inputs that this entity exposes.
+ //
+ GDclass *pClass = pEntity->GetClass();
+
+ if (pClass == NULL)
+ continue;
+
+ // check if class was already added
+ if ( classCache.Find( (int)pClass ) != -1 )
+ continue;
+
+ classCache.Insert( (int)pClass );
+
+ //
+ // Add this class' inputs to the list.
+ //
+ int nCount = pClass->GetInputCount();
+ for (int i = 0; i < nCount; i++)
+ {
+ CClassInput *pInput = pClass->GetInput(i);
+ bool bAddInput = true;
+
+ //
+ // Don't add the input to the combo box if another input with the same name
+ // and type is already there.
+ //
+ int nIndex = m_ComboInput.FindStringExact(-1, pInput->GetName());
+ if (nIndex != CB_ERR)
+ {
+ CClassInput *pExistingInput = (CClassInput *)m_ComboInput.GetItemDataPtr(nIndex);
+ if (pExistingInput->GetType() == pInput->GetType())
+ {
+ bAddInput = false;
+ }
+ }
+
+ if (bAddInput)
+ {
+ nIndex = m_ComboInput.AddString(pInput->GetName());
+ if (nIndex >= 0)
+ {
+ m_ComboInput.SetItemDataPtr(nIndex, pInput);
+ }
+ }
+ }
+ }
+
+ m_ComboInput.SetRedraw(TRUE);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Fills the list of outputs with outputs common to all the selected entities.
+//-----------------------------------------------------------------------------
+void COP_Output::FillOutputList(void)
+{
+ if ( m_EntityList.Count() == 0 )
+ {
+ return;
+ }
+
+ //
+ // Determine what the currently selected output is (if any).
+ //
+ CClassOutput *pSelectedOutput;
+ int nOutput = m_ComboOutput.GetCurSel();
+ if (nOutput != CB_ERR)
+ {
+ pSelectedOutput = (CClassOutput *)m_ComboOutput.GetItemDataPtr(nOutput);
+ }
+ else
+ {
+ pSelectedOutput = NULL;
+ }
+
+ //
+ // Add the entity outputs to the outputs combo box.
+ //
+ m_ComboOutput.SetRedraw(FALSE);
+ m_ComboOutput.ResetContent();
+
+ bool bFirst = true;
+
+ FOR_EACH_OBJ( m_EntityList, pos )
+ {
+ CMapEntity *pEntity = m_EntityList.Element(pos);
+
+ if (bFirst)
+ {
+ //
+ // The first entity adds its outputs to the list.
+ //
+ AddEntityOutputs(pEntity);
+ bFirst = false;
+ }
+ else
+ {
+ //
+ // All subsequent entities filter the output list.
+ //
+ FilterEntityOutputs(pEntity);
+ }
+ }
+
+ if (m_ComboOutput.GetCount() == 0)
+ {
+ m_ComboOutput.EnableWindow(false);
+ }
+
+ m_ComboOutput.SetRedraw(TRUE);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Fills the list of targets with entities that have "targetname" keys.
+//-----------------------------------------------------------------------------
+void COP_Output::FillTargetList(void)
+{
+ m_bIgnoreTextChanged = true;
+ m_ComboTarget.SetEntityList(m_pMapEntityList);
+ m_bIgnoreTextChanged = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Removes all outputs from the outputs combo box that are NOT present
+// in the given entity's output list. Used when multiple entities are
+// selected into the Entity Properties dialog.
+// Input : pEntity - Entity to use for filter.
+//-----------------------------------------------------------------------------
+void COP_Output::FilterEntityOutputs(CMapEntity *pEntity)
+{
+ //
+ // Make sure that this entity has a valid class to use for filtering.
+ //
+ GDclass *pClass = pEntity->GetClass();
+ if (pClass == NULL)
+ {
+ return;
+ }
+
+ //
+ // Remove any outputs from the combo box that are not in the class.
+ //
+ char szText[MAX_PATH];
+
+ int nCount = m_ComboOutput.GetCount();
+ if (nCount > 0)
+ {
+ for (int i = nCount - 1; i >= 0; i--)
+ {
+ if (m_ComboOutput.GetLBText(i, szText) != CB_ERR)
+ {
+ if (pClass->FindOutput(szText) == NULL)
+ {
+ m_ComboOutput.DeleteString(i);
+ }
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COP_Output::FilterOutputList(void)
+{
+ // dvs: Possibly unnecessary. For example, if they choose an input, then
+ // choose an incompatible output, the input will become red to indicate
+ // the incompatibilty. So maybe the outputs can always contain the set of
+ // all outputs common to the selected entities.
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Filters the list of inputs based on the current selected target.
+//-----------------------------------------------------------------------------
+void COP_Output::FilterInputList(void)
+{
+ char szTarget[MAX_ENTITY_NAME_LEN];
+ CMapEntityList *pTargets = GetTarget(szTarget, sizeof(szTarget));
+
+ if (pTargets != NULL)
+ {
+ //
+ // Remove all items from the inputs combo that:
+ //
+ // 1) Are not compatible with the currently selected output, OR
+ // 2) Are not found in the currently selected targets list.
+ //
+ int nCount = m_ComboInput.GetCount();
+ if (nCount > 0)
+ {
+ for (int i = nCount - 1; i >= 0; i--)
+ {
+ CClassInput *pInput = (CClassInput *)m_ComboInput.GetItemDataPtr(i);
+ if (!MapEntityList_HasInput(pTargets, pInput->GetName(), pInput->GetType()))
+ {
+ m_ComboInput.DeleteString(i);
+ }
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COP_Output::FilterTargetList(void)
+{
+#if 0 // Not used...
+ char szInput[MAX_IO_NAME_LEN];
+ CClassInput *pInput = GetInput(szInput, sizeof(szInput));
+
+ //
+ // Remove all items from the targets combo that:
+ //
+ // 1) Do not have the selected input name OR
+ // 2) Do not have inputs that are compatible with the selected output.
+ //
+ int nCount = m_ComboTarget.GetCount();
+ if (nCount > 0)
+ {
+ for (int i = nCount - 1; i >= 0; i--)
+ {
+ CMapEntityList *pTargets = (CMapEntityList *)m_ComboTarget.GetItemDataPtr(i);
+
+ if (!MapEntityList_HasInput(pTargets, pInput->GetName(), pInput->GetType()))
+ {
+ m_ComboTarget.DeleteString(i);
+ }
+ }
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the currently selected input, NULL if unknown.
+// Input : szInput - Receives the text in the Input combo edit control.
+// nSize - Size of buffer pointed to by szInput.
+//-----------------------------------------------------------------------------
+CClassInput *COP_Output::GetInput(char *szInput, int nSize)
+{
+ szInput[0] = '\0';
+
+ int nCurSel = m_ComboInput.GetCurSel();
+ if (nCurSel == CB_ERR)
+ {
+ if (m_ComboInput.GetWindowText(szInput, nSize) > 0)
+ {
+ nCurSel = m_ComboInput.FindStringExact(-1, szInput);
+ }
+ }
+
+ CClassInput *pInput = NULL;
+ if (nCurSel != CB_ERR)
+ {
+ m_ComboInput.GetLBText(nCurSel, szInput);
+ pInput = (CClassInput *)m_ComboInput.GetItemDataPtr(nCurSel);
+ }
+
+ return(pInput);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the currently selected output, NULL if unknown.
+// Input : szOutput - Receives the text in the Output combo edit control.
+// nSize - Size of buffer pointed to by szOutput.
+//-----------------------------------------------------------------------------
+CClassOutput *COP_Output::GetOutput(char *szOutput, int nSize)
+{
+ szOutput[0] = '\0';
+
+ int nCurSel = m_ComboOutput.GetCurSel();
+ if (nCurSel == CB_ERR)
+ {
+ if (m_ComboOutput.GetWindowText(szOutput, nSize) > 0)
+ {
+ nCurSel = m_ComboOutput.FindStringExact(-1, szOutput);
+ }
+ }
+
+ CClassOutput *pOutput = NULL;
+ if (nCurSel != CB_ERR)
+ {
+ m_ComboOutput.GetLBText(nCurSel, szOutput);
+ pOutput = (CClassOutput *)m_ComboOutput.GetItemDataPtr(nCurSel);
+ }
+
+ return(pOutput);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the currently selected target list, NULL if unknown.
+// Input : szTarget - Receives the text in the Target combo edit control.
+// nSize - Size of buffer pointed to by szTarget.
+//-----------------------------------------------------------------------------
+CMapEntityList *COP_Output::GetTarget(char *szTarget, int nSize)
+{
+ szTarget[0] = '\0';
+
+ CString str = m_ComboTarget.GetCurrentItem();
+ Q_strncpy( szTarget, str, nSize );
+
+ return m_ComboTarget.GetSubEntityList( szTarget );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when the contents of the delay edit box change.
+//-----------------------------------------------------------------------------
+void COP_Output::OnEditDelay(void)
+{
+ UpdateEditedDelays();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when the contents of the target combo edit box change.
+//-----------------------------------------------------------------------------
+void COP_Output::OnFireOnce(void)
+{
+ UpdateEditedFireOnce();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when they change the "Show Hidden Targets" checkbox.
+//-----------------------------------------------------------------------------
+void COP_Output::OnShowHiddenTargetsAsBroken()
+{
+ // Remember the last state of this checkbox.
+ Options.general.bShowHiddenTargetsAsBroken = (m_ctlShowHiddenTargetsAsBroken.GetCheck() != FALSE);
+
+ // Refresh.
+ int nCount = m_ListCtrl.GetItemCount();
+ for ( int i=0; i < nCount; i++ )
+ {
+ UpdateItemValidity( i );
+ }
+ //UpdateConnectionList();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: React to the input combo box being changed
+//-----------------------------------------------------------------------------
+void COP_Output::InputChanged(void)
+{
+ // Updating the listbox data, will trigger the edit
+ // controls to update. They don't need to be
+ bSkipEditControlRefresh = true;
+
+ char szInput[MAX_IO_NAME_LEN];
+ CClassInput *pInput = GetInput(szInput, sizeof(szInput));
+ UpdateCombosForSelectedInput(pInput);
+ UpdateEditedInputs();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when selection of input combo box chages
+//-----------------------------------------------------------------------------
+void COP_Output::OnSelChangeInput(void)
+{
+ InputChanged();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when the contents of the input combo edit box change.
+//-----------------------------------------------------------------------------
+void COP_Output::OnEditUpdateInput(void)
+{
+ InputChanged();
+}
+
+
+//------------------------------------------------------------------------------
+// Purpose: React to the output combo box being changed
+//------------------------------------------------------------------------------
+void COP_Output::OutputChanged(void)
+{
+ // Updating the listbox data, will trigger the edit
+ // controls to update. They don't need to be
+ bSkipEditControlRefresh = true;
+
+ char szOutput[MAX_IO_NAME_LEN];
+ CClassOutput *pOutput = GetOutput(szOutput, sizeof(szOutput));
+ UpdateCombosForSelectedOutput(pOutput);
+ UpdateEditedOutputs();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when selection of output combo box chages
+//-----------------------------------------------------------------------------
+void COP_Output::OnSelChangeOutput(void)
+{
+ OutputChanged();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when the contents of the output combo edit box change.
+//-----------------------------------------------------------------------------
+void COP_Output::OnEditUpdateOutput(void)
+{
+ OutputChanged();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when selection of parameter combo box chages
+//-----------------------------------------------------------------------------
+void COP_Output::OnSelChangeParam(void)
+{
+ // If user picked <none> selection (the only valid one) clear window text
+ CComboBox *pParamEdit = ( CComboBox* )GetDlgItem( IDC_EDIT_CONN_PARAM );
+ if (pParamEdit->GetCurSel() != CB_ERR)
+ {
+ pParamEdit->SetWindowText("");
+ }
+
+ UpdateEditedParams();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when the contents of the parameter combo edit box change.
+//-----------------------------------------------------------------------------
+void COP_Output::OnEditUpdateParam(void)
+{
+ UpdateEditedParams();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates the dialog based on the currently selected input.
+// Input : pInput - Pointer to the input that is selected, NULL if none or
+// ambiguous/unresolved.
+//-----------------------------------------------------------------------------
+void COP_Output::UpdateCombosForSelectedInput(CClassInput *pInput)
+{
+ // Enable / Disable param box based on input type if allowed
+ if (!m_bNoParamEdit)
+ {
+ CComboBox *pParamCombo = (CComboBox *)GetDlgItem(IDC_EDIT_CONN_PARAM);
+ bool bEnable = ((!pInput) || (pInput && (pInput->GetType() != iotVoid)));
+ if (!bEnable)
+ {
+ // Save the param so we can restore it if they switch right back.
+ CString strTemp;
+ pParamCombo->GetWindowText(strTemp);
+ if (strTemp.Compare(PARAM_STRING_NONE))
+ {
+ m_strLastParam = strTemp;
+ }
+
+ // Switch back to <none> if we're disabling the parameter combo.
+ pParamCombo->SetCurSel(0);
+ }
+ else if (!m_strLastParam.IsEmpty())
+ {
+ pParamCombo->SetWindowText(m_strLastParam);
+ }
+
+ UpdateEditedParams();
+ pParamCombo->EnableWindow(bEnable);
+ m_bEntityParamTarget = pInput && (pInput->GetType() == iotEHandle);
+ GetDlgItem(IDC_PICK_ENTITY_PARAM)->EnableWindow( m_bEntityParamTarget );
+ }
+
+ if (pInput != NULL)
+ {
+ //
+ // Known input, render it in black.
+ //
+ m_ComboInput.SetTextColor(RGB(0, 0, 0));
+ }
+ else
+ {
+ //
+ // Unknown input, render it in red.
+ //
+ m_ComboInput.SetTextColor(RGB(255, 0, 0));
+ }
+ m_ComboInput.RedrawWindow();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates the dialog based on the currently selected output.
+// Input : pOutput - Pointer to the output that is selected, NULL if none or
+// ambiguous/unresolved.
+//-----------------------------------------------------------------------------
+void COP_Output::UpdateCombosForSelectedOutput(CClassOutput *pOutput)
+{
+ if (pOutput != NULL)
+ {
+ //
+ // Known output, render it in black.
+ //
+ m_ComboOutput.SetTextColor(RGB(0, 0, 0));
+ }
+ else
+ {
+ //
+ // Unknown output, render it in red.
+ //
+ m_ComboOutput.SetTextColor(RGB(255, 0, 0));
+ }
+ m_ComboOutput.RedrawWindow();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Stops entity picking.
+//-----------------------------------------------------------------------------
+void COP_Output::StopPicking(void)
+{
+ if (m_bPickingEntities)
+ {
+ m_bPickingEntities = false;
+ ToolManager()->SetTool(TOOL_POINTER);
+
+ CButton *pButton = (CButton *)GetDlgItem(IDC_PICK_ENTITY);
+ if (pButton)
+ {
+ pButton->SetCheck(0);
+ }
+
+ pButton = (CButton *)GetDlgItem(IDC_PICK_ENTITY_PARAM);
+ if (pButton)
+ {
+ pButton->SetCheck(0);
+ }
+
+ if ( m_ComboTarget.IsWindowEnabled() )
+ {
+ GetDlgItem(IDC_PICK_ENTITY)->EnableWindow( true );
+ }
+
+ CComboBox* pParamEdit = ( CComboBox* )GetDlgItem( IDC_EDIT_CONN_PARAM );
+ if ( pParamEdit->IsWindowEnabled() )
+ {
+ GetDlgItem(IDC_PICK_ENTITY_PARAM)->EnableWindow( m_bEntityParamTarget );
+ }
+ }
+}
+
+void COP_Output::OnSize( UINT nType, int cx, int cy )
+{
+ m_AnchorMgr.OnSize();
+}