summaryrefslogtreecommitdiff
path: root/tools
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 /tools
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'tools')
-rw-r--r--tools/actbusy/actbusy.vpc54
-rw-r--r--tools/actbusy/actbusydoc.cpp184
-rw-r--r--tools/actbusy/actbusydoc.h71
-rw-r--r--tools/actbusy/actbusytool.cpp1224
-rw-r--r--tools/actbusy/actbusytool.h38
-rw-r--r--tools/commedit/commedit.vpc64
-rw-r--r--tools/commedit/commeditdoc.cpp443
-rw-r--r--tools/commedit/commeditdoc.h92
-rw-r--r--tools/commedit/commedittool.cpp1284
-rw-r--r--tools/commedit/commedittool.h231
-rw-r--r--tools/commedit/commentarynodebrowserpanel.cpp283
-rw-r--r--tools/commedit/commentarynodebrowserpanel.h67
-rw-r--r--tools/commedit/commentarypropertiespanel.cpp458
-rw-r--r--tools/commedit/commentarypropertiespanel.h113
-rw-r--r--tools/commedit/dmecommentarynodeentity.cpp339
-rw-r--r--tools/commedit/dmecommentarynodeentity.h100
-rw-r--r--tools/commedit/entityreportpanel.cpp581
-rw-r--r--tools/foundry/DmeVMFEntity.cpp246
-rw-r--r--tools/foundry/DmeVMFEntity.h88
-rw-r--r--tools/foundry/entityreportpanel.cpp639
-rw-r--r--tools/foundry/entityreportpanel.h122
-rw-r--r--tools/foundry/foundry.vpc67
-rw-r--r--tools/foundry/foundrydoc.cpp345
-rw-r--r--tools/foundry/foundrydoc.h83
-rw-r--r--tools/foundry/foundrytool.cpp1172
-rw-r--r--tools/foundry/foundrytool.h65
-rw-r--r--tools/gameevents/gameeventeditdoc.cpp182
-rw-r--r--tools/gameevents/gameeventeditdoc.h94
-rw-r--r--tools/gameevents/gameeventeditpanel.cpp240
-rw-r--r--tools/gameevents/gameeventeditpanel.h90
-rw-r--r--tools/gameevents/gameevents.cpp625
-rw-r--r--tools/gameevents/gameevents.vpc60
-rw-r--r--tools/pet/particlesystemdefinitionbrowser.cpp599
-rw-r--r--tools/pet/particlesystemdefinitionbrowser.h90
-rw-r--r--tools/pet/particlesystempropertiescontainer.cpp73
-rw-r--r--tools/pet/particlesystempropertiescontainer.h45
-rw-r--r--tools/pet/pet.vpc64
-rw-r--r--tools/pet/petdoc.cpp536
-rw-r--r--tools/pet/petdoc.h122
-rw-r--r--tools/pet/pettool.cpp1078
-rw-r--r--tools/pet/pettool.h209
-rw-r--r--tools/sampletool/cbase.cpp9
-rw-r--r--tools/sampletool/cbase.h46
-rw-r--r--tools/sampletool/sampletool.cpp342
-rw-r--r--tools/sampletool/sampletool.vpc79
-rw-r--r--tools/toolutils/BaseToolSystem.cpp1156
-rw-r--r--tools/toolutils/ConsolePage.cpp45
-rw-r--r--tools/toolutils/ToolFileMenuButton.cpp251
-rw-r--r--tools/toolutils/ToolHelpMenuButton.cpp60
-rw-r--r--tools/toolutils/ToolMenuButton.cpp185
-rw-r--r--tools/toolutils/ToolSwitchMenuButton.cpp72
-rw-r--r--tools/toolutils/ToolUI.cpp118
-rw-r--r--tools/toolutils/ToolUI.h66
-rw-r--r--tools/toolutils/attributeelementchoicelist.cpp137
-rw-r--r--tools/toolutils/basepropertiescontainer.cpp47
-rw-r--r--tools/toolutils/basestatusbar.cpp151
-rw-r--r--tools/toolutils/miniviewport.cpp457
-rw-r--r--tools/toolutils/recentfilelist.cpp157
-rw-r--r--tools/toolutils/savewindowpositions.cpp286
-rw-r--r--tools/toolutils/tool_main.cpp233
-rw-r--r--tools/toolutils/tooleditmenubutton.cpp131
-rw-r--r--tools/toolutils/toolmenubar.cpp132
-rw-r--r--tools/toolutils/toolutils.vpc54
-rw-r--r--tools/toolutils/vgui_tools.cpp67
-rw-r--r--tools/vcdblock/dmevmfentity.cpp664
-rw-r--r--tools/vcdblock/dmevmfentity.h131
-rw-r--r--tools/vcdblock/infotargetbrowserpanel.cpp297
-rw-r--r--tools/vcdblock/infotargetbrowserpanel.h68
-rw-r--r--tools/vcdblock/infotargetpropertiespanel.cpp225
-rw-r--r--tools/vcdblock/infotargetpropertiespanel.h76
-rw-r--r--tools/vcdblock/vcdblock.vpc64
-rw-r--r--tools/vcdblock/vcdblockdoc.cpp630
-rw-r--r--tools/vcdblock/vcdblockdoc.h108
-rw-r--r--tools/vcdblock/vcdblocktool.cpp1300
-rw-r--r--tools/vcdblock/vcdblocktool.h239
-rw-r--r--tools/vmt/vmt.vpc59
-rw-r--r--tools/vmt/vmtdoc.cpp1078
-rw-r--r--tools/vmt/vmtdoc.h133
-rw-r--r--tools/vmt/vmttool.cpp1337
-rw-r--r--tools/vmt/vmttool.h50
80 files changed, 23300 insertions, 0 deletions
diff --git a/tools/actbusy/actbusy.vpc b/tools/actbusy/actbusy.vpc
new file mode 100644
index 0000000..782033a
--- /dev/null
+++ b/tools/actbusy/actbusy.vpc
@@ -0,0 +1,54 @@
+//-----------------------------------------------------------------------------
+// ACTBUSY.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin\tools"
+
+$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+
+$Configuration
+{
+ $Linker
+ {
+ $AdditionalDependencies "$BASE psapi.lib"
+ }
+}
+
+$Project "Actbusy"
+{
+ $Folder "Source Files"
+ {
+ $File "actbusydoc.cpp"
+ $File "actbusytool.cpp"
+ $File "$SRCDIR\public\interpolatortypes.cpp"
+ $File "$SRCDIR\public\movieobjects\movieobjects.cpp"
+ $File "$SRCDIR\public\registry.cpp"
+ $File "$SRCDIR\public\vgui_controls\vgui_controls.cpp"
+ }
+
+ $Folder "Header Files"
+ {
+ $File "actbusydoc.h"
+ $File "actbusytool.h"
+ $File "$SRCDIR\public\interpolatortypes.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib dmxloader
+ $Lib datamodel
+ $Lib dme_controls
+ $Lib dmserializers
+ $Lib mathlib
+ $Lib matsys_controls
+ $Lib movieobjects
+ $Lib sfmobjects
+ $Lib tier2
+ $Lib tier3
+ $Lib toolutils
+ $Lib vgui_controls
+ }
+}
diff --git a/tools/actbusy/actbusydoc.cpp b/tools/actbusy/actbusydoc.cpp
new file mode 100644
index 0000000..43116b4
--- /dev/null
+++ b/tools/actbusy/actbusydoc.cpp
@@ -0,0 +1,184 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "actbusydoc.h"
+#include "datamodel/dmelement.h"
+#include "actbusytool.h"
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CActBusyDoc::CActBusyDoc( IActBusyDocCallback *pCallback ) : m_pCallback( pCallback )
+{
+ m_hRoot = NULL;
+ m_pFileName[0] = 0;
+ m_bDirty = false;
+ g_pDataModel->InstallNotificationCallback( this );
+}
+
+CActBusyDoc::~CActBusyDoc()
+{
+ g_pDataModel->RemoveNotificationCallback( this );
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from INotifyUI
+//-----------------------------------------------------------------------------
+void CActBusyDoc::NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ OnDataChanged( pReason, nNotifySource, nNotifyFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the file name
+//-----------------------------------------------------------------------------
+const char *CActBusyDoc::GetFileName()
+{
+ return m_pFileName;
+}
+
+void CActBusyDoc::SetFileName( const char *pFileName )
+{
+ Q_strncpy( m_pFileName, pFileName, sizeof( m_pFileName ) );
+ SetDirty( true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Dirty bits
+//-----------------------------------------------------------------------------
+void CActBusyDoc::SetDirty( bool bDirty )
+{
+ m_bDirty = bDirty;
+}
+
+bool CActBusyDoc::IsDirty() const
+{
+ return m_bDirty;
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates a new act busy
+//-----------------------------------------------------------------------------
+void CActBusyDoc::CreateNew()
+{
+ Assert( !m_hRoot.Get() );
+
+ // This is not undoable
+ CDisableUndoScopeGuard guard;
+
+ Q_strncpy( m_pFileName, "untitled", sizeof( m_pFileName ) );
+ DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( m_pFileName );
+
+ // Create the main element
+ m_hRoot = g_pDataModel->CreateElement( "DmElement", "ActBusyList", fileid );
+ if ( m_hRoot == DMELEMENT_HANDLE_INVALID )
+ return;
+
+ g_pDataModel->SetFileRoot( fileid, m_hRoot );
+
+ // Each act busy list needs to have an editortype associated with it so it displays nicely in editors
+ m_hRoot->SetValue( "editorType", "actBusyList" );
+ m_hRoot->AddAttribute( "children", AT_ELEMENT_ARRAY );
+
+ SetDirty( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Saves/loads from file
+//-----------------------------------------------------------------------------
+bool CActBusyDoc::LoadFromFile( const char *pFileName )
+{
+ Assert( !m_hRoot.Get() );
+
+ SetDirty( false );
+ m_hRoot = NULL;
+
+ Q_strncpy( m_pFileName, pFileName, sizeof( m_pFileName ) );
+ if ( !m_pFileName[0] )
+ return false;
+
+ // This is not undoable
+ CDisableUndoScopeGuard guard;
+
+ CDmElement *root = NULL;
+ g_pDataModel->RestoreFromFile( m_pFileName, NULL, "actbusy", &root );
+ m_hRoot = root;
+ OnDataChanged( "CActBusyDoc::LoadFromFile", NOTIFY_SOURCE_APPLICATION, NOTIFY_CHANGE_TOPOLOGICAL );
+ SetDirty( false );
+ return true;
+}
+
+void CActBusyDoc::SaveToFile( )
+{
+ if ( m_hRoot.Get() && m_pFileName && m_pFileName[0] )
+ {
+ g_pDataModel->SaveToFile( m_pFileName, NULL, "keyvalues", "actbusy", m_hRoot );
+ }
+
+ SetDirty( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates a new act busy
+//-----------------------------------------------------------------------------
+void CActBusyDoc::CreateActBusy()
+{
+ CDmElement *pRoot = GetRootObject();
+ if ( !pRoot )
+ return;
+
+ // This is undoable
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Add ActBusy", "Add ActBusy" );
+
+ DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( m_pFileName );
+
+ // Create the main element
+ CDmeHandle<CDmElement> hActBusy = g_pDataModel->CreateElement( "DmElement", "ActBusy", fileid );
+ if ( hActBusy == DMELEMENT_HANDLE_INVALID )
+ return;
+
+ hActBusy->SetValue( "editorType", "actBusy" );
+ hActBusy->SetValue( "busy_anim", "" );
+ hActBusy->SetValue( "entry_anim", "" );
+ hActBusy->SetValue( "exit_anim", "" );
+ hActBusy->SetValue( "busy_sequence", "" );
+ hActBusy->SetValue( "entry_sequence", "" );
+ hActBusy->SetValue( "exit_sequence", "" );
+ hActBusy->SetValue( "min_time", 0.0f );
+ hActBusy->SetValue( "max_time", 0.0f );
+ hActBusy->SetValue( "interrupts", "BA_INT_NONE" );
+
+ CDmrElementArray<> children( pRoot, "children" );
+ children.AddToTail( hActBusy );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the root object
+//-----------------------------------------------------------------------------
+CDmElement *CActBusyDoc::GetRootObject()
+{
+ return m_hRoot;
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when data changes
+//-----------------------------------------------------------------------------
+void CActBusyDoc::OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ SetDirty( nNotifyFlags & NOTIFY_SETDIRTYFLAG ? true : false );
+ m_pCallback->OnDocChanged( pReason, nNotifySource, nNotifyFlags );
+}
diff --git a/tools/actbusy/actbusydoc.h b/tools/actbusy/actbusydoc.h
new file mode 100644
index 0000000..ea0eee1
--- /dev/null
+++ b/tools/actbusy/actbusydoc.h
@@ -0,0 +1,71 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#ifndef ACTBUSYDOC_H
+#define ACTBUSYDOC_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "dme_controls/inotifyui.h"
+#include "datamodel/dmehandle.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class IActBusyDocCallback;
+
+
+//-----------------------------------------------------------------------------
+// Contains all editable state
+//-----------------------------------------------------------------------------
+class CActBusyDoc : public IDmNotify
+{
+public:
+ CActBusyDoc( IActBusyDocCallback *pCallback );
+ ~CActBusyDoc();
+
+ // Inherited from INotifyUI
+ virtual void NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Sets/Gets the file name
+ const char *GetFileName();
+ void SetFileName( const char *pFileName );
+
+ // Dirty bits (has it changed since the last time it was saved?)
+ void SetDirty( bool bDirty );
+ bool IsDirty() const;
+
+ // Creates a new act busy list
+ void CreateNew();
+
+ // Saves/loads from file
+ bool LoadFromFile( const char *pFileName );
+ void SaveToFile( );
+
+ // Returns the root object
+ CDmElement *GetRootObject();
+
+ // Called when data changes
+ void OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Creates a new actbusy
+ void CreateActBusy();
+
+private:
+ IActBusyDocCallback *m_pCallback;
+ CDmeHandle< CDmElement > m_hRoot;
+ char m_pFileName[512];
+ bool m_bDirty;
+};
+
+
+#endif // ACTBUSYDOC_H
diff --git a/tools/actbusy/actbusytool.cpp b/tools/actbusy/actbusytool.cpp
new file mode 100644
index 0000000..1b79a40
--- /dev/null
+++ b/tools/actbusy/actbusytool.cpp
@@ -0,0 +1,1224 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Act busy tool; main UI smarts class
+//
+//=============================================================================
+
+#include "toolutils/basetoolsystem.h"
+#include "toolutils/recentfilelist.h"
+#include "toolutils/toolmenubar.h"
+#include "toolutils/toolswitchmenubutton.h"
+#include "toolutils/toolfilemenubutton.h"
+#include "toolutils/tooleditmenubutton.h"
+#include "toolutils/toolmenubutton.h"
+#include "vgui_controls/Menu.h"
+#include "tier1/KeyValues.h"
+#include "toolutils/enginetools_int.h"
+#include "toolframework/ienginetool.h"
+#include "vgui/IInput.h"
+#include "vgui/KeyCode.h"
+#include "vgui_controls/FileOpenDialog.h"
+#include "filesystem.h"
+#include "actbusydoc.h"
+#include "vgui/ilocalize.h"
+#include "dme_controls/elementpropertiestree.h"
+#include "actbusytool.h"
+#include "movieobjects/dmeeditortypedictionary.h"
+#include "dme_controls/attributestringchoicepanel.h"
+#include "matsys_controls/mdlsequencepicker.h"
+#include "istudiorender.h"
+#include "materialsystem/imaterialsystem.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "toolutils/toolwindowfactory.h"
+#include "toolutils/basepropertiescontainer.h"
+#include "toolutils/savewindowpositions.h"
+#include "tier2/fileutils.h"
+#include "tier3/tier3.h"
+#include "vgui/ivgui.h"
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Singleton interfaces
+//-----------------------------------------------------------------------------
+CDmeEditorTypeDictionary *g_pEditorTypeDict;
+
+
+//-----------------------------------------------------------------------------
+// Methods needed by scenedatabase. They have to live here instead of toolutils
+// because this is a DLL but toolutils is only a static library
+//-----------------------------------------------------------------------------
+const char *GetVGuiControlsModuleName()
+{
+ return "ActBusyTool";
+}
+
+//-----------------------------------------------------------------------------
+// Connect, disconnect
+//-----------------------------------------------------------------------------
+bool ConnectTools( CreateInterfaceFn factory )
+{
+ return (g_pMDLCache != NULL) && (studiorender != NULL) && (materials != NULL) && (g_pMatSystemSurface != NULL);
+}
+
+void DisconnectTools( )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Implementation of the act busy tool
+//-----------------------------------------------------------------------------
+class CActBusyTool : public CBaseToolSystem, public IFileMenuCallbacks, public IActBusyDocCallback
+{
+ DECLARE_CLASS_SIMPLE( CActBusyTool, CBaseToolSystem );
+
+public:
+ CActBusyTool();
+
+ // Inherited from IToolSystem
+ virtual const char *GetToolName() { return "ActBusy Script Editor"; }
+ virtual const char *GetBindingsContextFile() { return "cfg/ActBusy.kb"; }
+ virtual bool Init();
+ virtual void Shutdown();
+ virtual bool CanQuit();
+
+ // Inherited from IFileMenuCallbacks
+ virtual int GetFileMenuItemsEnabled( );
+ virtual void AddRecentFilesToMenu( vgui::Menu *menu );
+ virtual bool GetPerforceFileName( char *pFileName, int nMaxLen );
+ virtual vgui::Panel* GetRootPanel() { return this; }
+
+ // Inherited from IActBusyDocCallback
+ virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Inherited from CBaseToolSystem
+ virtual vgui::HScheme GetToolScheme();
+ virtual vgui::Menu *CreateActionMenu( vgui::Panel *pParent );
+ virtual void OnCommand( const char *cmd );
+ virtual const char *GetRegistryName() { return "ActBusy"; }
+ virtual vgui::MenuBar *CreateMenuBar( CBaseToolSystem *pParent );
+ virtual void OnToolActivate();
+ virtual void OnToolDeactivate();
+ virtual CActBusyDoc *GetDocument();
+ virtual CBasePropertiesContainer *GetProperties();
+ virtual CMDLSequencePicker *GetSequencePicker();
+ virtual void SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual void OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues );
+
+public:
+ // Commands related to the file menu
+ MESSAGE_FUNC( OnNew, "OnNew" );
+ MESSAGE_FUNC( OnOpen, "OnOpen" );
+ MESSAGE_FUNC( OnSave, "OnSave" );
+ MESSAGE_FUNC( OnSaveAs, "OnSaveAs" );
+ MESSAGE_FUNC( OnClose, "OnClose" );
+ MESSAGE_FUNC( OnCloseNoSave, "OnCloseNoSave" );
+ MESSAGE_FUNC( OnMarkNotDirty, "OnMarkNotDirty" );
+ MESSAGE_FUNC( OnExit, "OnExit" );
+ void PerformNew();
+ void OpenFileFromHistory( int slot, const char *pCommand );
+ void OpenSpecificFile( const char *pFileName );
+
+ // Commands related to the edit menu
+ KEYBINDING_FUNC( undo, KEY_Z, vgui::MODIFIER_CONTROL, OnUndo, "#undo_help", 0 );
+ KEYBINDING_FUNC( redo, KEY_Z, vgui::MODIFIER_CONTROL | vgui::MODIFIER_SHIFT, OnRedo, "#redo_help", 0 );
+ void OnDescribeUndo();
+
+ // Commands related to the actbusy menu
+ void OnNewActBusy();
+ void OnDeleteActBusy();
+
+private:
+ // Flags for HideStandardFields
+ enum EditorTypeStandardFields_t
+ {
+ EDITOR_FIELD_NAME = 0x1,
+ EDITOR_FIELD_TYPE = 0x2,
+ EDITOR_FIELD_ID = 0x4,
+ EDITOR_FIELD_EDITORTYPE = 0x8,
+ };
+
+ void HideStandardFields( CDmeEditorType *pEditorType, int nFieldFlags );
+
+ // Creates a new document
+ void NewDocument( );
+
+ // Loads up a new document
+ bool LoadDocument( const char *pDocName );
+
+ // Updates the menu bar based on the current file
+ void UpdateMenuBar( );
+
+ // Shows element properties
+ void ShowElementProperties( );
+
+ // Create custom editors
+ void InitEditorDict();
+
+ void CreateTools( CActBusyDoc *doc );
+ void InitTools();
+ void DestroyTools();
+
+ void ToggleToolWindow( Panel *tool, const char *toolName );
+ void ShowToolWindow( Panel *tool, const char *toolName, bool visible );
+
+ void OnToggleProperties();
+ void OnToggleSequencePicker();
+ void OnDefaultLayout();
+
+ void DestroyToolContainers();
+
+ virtual const char *GetLogoTextureName();
+
+private:
+ // All editable data
+ CActBusyDoc *m_pDoc;
+
+ // The menu bar
+ CToolFileMenuBar *m_pMenuBar;
+
+ // Element properties for editing actbusy
+ vgui::DHANDLE< CBasePropertiesContainer > m_hProperties;
+ // The sequence picker!
+ vgui::DHANDLE< CMDLSequencePicker > m_hMDLSequencePicker;
+
+ CToolWindowFactory< ToolWindow > m_ToolWindowFactory;
+
+ CUtlVector< DmElementHandle_t > m_toolElements;
+};
+
+
+//-----------------------------------------------------------------------------
+// Singleton
+//-----------------------------------------------------------------------------
+CActBusyTool *g_pActBusyTool = NULL;
+
+void CreateTools()
+{
+ g_pActBusyTool = new CActBusyTool();
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CActBusyTool::CActBusyTool()
+{
+ m_pMenuBar = NULL;
+ m_pDoc = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Init, shutdown
+//-----------------------------------------------------------------------------
+bool CActBusyTool::Init( )
+{
+ m_pDoc = NULL;
+ m_RecentFiles.LoadFromRegistry( GetRegistryName() );
+
+ // NOTE: This has to happen before BaseClass::Init
+ g_pVGuiLocalize->AddFile( "resource/toolactbusy_%language%.txt" );
+
+ if ( !BaseClass::Init( ) )
+ return false;
+
+ g_pDataModel->SetUndoDepth( 256 );
+
+ InitEditorDict();
+ return true;
+}
+
+void CActBusyTool::Shutdown()
+{
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+
+ {
+ CDisableUndoScopeGuard guard;
+ int nElements = m_toolElements.Count();
+ for ( int i = 0; i < nElements; ++i )
+ {
+ g_pDataModel->DestroyElement( m_toolElements[ i ] );
+ }
+ }
+
+ BaseClass::Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// Tool activation/deactivation
+//-----------------------------------------------------------------------------
+void CActBusyTool::OnToolActivate()
+{
+ BaseClass::OnToolActivate();
+}
+
+void CActBusyTool::OnToolDeactivate()
+{
+ BaseClass::OnToolDeactivate();
+}
+
+
+//-----------------------------------------------------------------------------
+// Hides standard fields
+//-----------------------------------------------------------------------------
+void CActBusyTool::HideStandardFields( CDmeEditorType *pEditorType, int nFieldFlags )
+{
+ CDmeEditorAttributeInfo *pInfo;
+
+ if ( nFieldFlags & EDITOR_FIELD_NAME )
+ {
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "name info", DMFILEID_INVALID );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "name", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+ }
+
+ if ( nFieldFlags & EDITOR_FIELD_TYPE )
+ {
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "type info", DMFILEID_INVALID );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "type", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+ }
+
+ if ( nFieldFlags & EDITOR_FIELD_ID )
+ {
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "id info", DMFILEID_INVALID );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "id", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+ }
+
+ if ( nFieldFlags & EDITOR_FIELD_EDITORTYPE )
+ {
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "editor type info", DMFILEID_INVALID );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "editorType", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Create custom editors
+//-----------------------------------------------------------------------------
+void CActBusyTool::InitEditorDict()
+{
+ CDmeEditorAttributeInfo *pInfo, *pArrayInfo;
+
+ // FIXME: This eventually will move to an .fgd-like file.
+ g_pEditorTypeDict = CreateElement< CDmeEditorTypeDictionary >( "DmeEditorTypeDictionary", DMFILEID_INVALID );
+ m_toolElements.AddToTail( g_pEditorTypeDict->GetHandle() );
+
+ CDmeEditorType *pActBusyList = CreateElement< CDmeEditorType >( "actBusyList", DMFILEID_INVALID );
+ HideStandardFields( pActBusyList, EDITOR_FIELD_NAME | EDITOR_FIELD_TYPE | EDITOR_FIELD_ID | EDITOR_FIELD_EDITORTYPE );
+ g_pEditorTypeDict->AddEditorType( pActBusyList );
+ m_toolElements.AddToTail( pActBusyList->GetHandle() );
+
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "children info", DMFILEID_INVALID );
+ pActBusyList->AddAttributeInfo( "children", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+ pArrayInfo = CreateElement< CDmeEditorAttributeInfo >( "hide text info", DMFILEID_INVALID );
+ pInfo->SetArrayInfo( pArrayInfo );
+ pArrayInfo->SetValue( "hideText", true );
+ m_toolElements.AddToTail( pArrayInfo->GetHandle() );
+
+ CDmeEditorType *pActBusyType = CreateElement< CDmeEditorType >( "actBusy", DMFILEID_INVALID );
+ HideStandardFields( pActBusyType, EDITOR_FIELD_TYPE | EDITOR_FIELD_ID | EDITOR_FIELD_EDITORTYPE );
+ m_toolElements.AddToTail( pActBusyType->GetHandle() );
+
+ // anims only accept activity names
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "busy anim info", DMFILEID_INVALID );
+ pActBusyType->AddAttributeInfo( "busy_anim", pInfo );
+ pInfo->m_Widget = "sequencepicker";
+ pInfo->SetValue( "texttype", "activityName" );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "entry anim info", DMFILEID_INVALID );
+ pActBusyType->AddAttributeInfo( "entry_anim", pInfo );
+ pInfo->m_Widget = "sequencepicker";
+ pInfo->SetValue( "texttype", "activityName" );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "exit anim info", DMFILEID_INVALID );
+ pActBusyType->AddAttributeInfo( "exit_anim", pInfo );
+ pInfo->m_Widget = "sequencepicker";
+ pInfo->SetValue( "texttype", "activityName" );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+
+ // sequences only accept sequence names
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "busy sequence info", DMFILEID_INVALID );
+ pActBusyType->AddAttributeInfo( "busy_sequence", pInfo );
+ pInfo->m_Widget = "sequencepicker";
+ pInfo->SetValue( "texttype", "sequenceName" );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "entry sequence info", DMFILEID_INVALID );
+ pActBusyType->AddAttributeInfo( "entry_sequence", pInfo );
+ pInfo->m_Widget = "sequencepicker";
+ pInfo->SetValue( "texttype", "sequenceName" );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "exit sequence info", DMFILEID_INVALID );
+ pActBusyType->AddAttributeInfo( "exit_sequence", pInfo );
+ pInfo->m_Widget = "sequencepicker";
+ pInfo->SetValue( "texttype", "sequenceName" );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+
+ CDmeEditorStringChoicesInfo *pChoicesInfo = CreateElement< CDmeEditorStringChoicesInfo >( "interrupts info", DMFILEID_INVALID );
+ pActBusyType->AddAttributeInfo( "interrupts", pChoicesInfo );
+ pChoicesInfo->m_Widget = "stringchoice";
+ m_toolElements.AddToTail( pChoicesInfo->AddChoice( "BA_INT_NONE", "No Interrupts" )->GetHandle() );
+ m_toolElements.AddToTail( pChoicesInfo->AddChoice( "BA_INT_DANGER", "Danger" )->GetHandle() );
+ m_toolElements.AddToTail( pChoicesInfo->AddChoice( "BA_INT_PLAYER", "Player" )->GetHandle() );
+ m_toolElements.AddToTail( pChoicesInfo->AddChoice( "BA_INT_AMBUSH", "Ambush" )->GetHandle() );
+ m_toolElements.AddToTail( pChoicesInfo->AddChoice( "BA_INT_COMBAT", "Combat" )->GetHandle() );
+ m_toolElements.AddToTail( pChoicesInfo->AddChoice( "BA_INT_ZOMBIESLUMP", "Zombie Slump" )->GetHandle() );
+ m_toolElements.AddToTail( pChoicesInfo->GetHandle() );
+
+ g_pEditorTypeDict->AddEditorType( pActBusyType );
+}
+
+//-----------------------------------------------------------------------------
+//
+// The View menu
+//
+//-----------------------------------------------------------------------------
+class CActBusyViewMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CActBusyViewMenuButton, CToolMenuButton );
+public:
+ CActBusyViewMenuButton( CActBusyTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+
+private:
+ CActBusyTool *m_pTool;
+};
+
+CActBusyViewMenuButton::CActBusyViewMenuButton( CActBusyTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ m_pTool = parent;
+
+ AddCheckableMenuItem( "properties", "#ActBusyProperties", new KeyValues( "Command", "command", "OnToggleProperties" ), pActionSignalTarget );
+ AddCheckableMenuItem( "picker", "#ActBusyViewSequencePicker", new KeyValues( "Command", "command", "OnToggleSequencePicker" ), pActionSignalTarget );
+
+ AddSeparator();
+ AddMenuItem( "defaultlayout", "#ActBusyViewDefault", new KeyValues ( "Command", "command", "OnDefaultLayout"), pActionSignalTarget );
+
+ SetMenu(m_pMenu);
+}
+
+void CActBusyViewMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ int id;
+
+ CActBusyDoc *pDoc = m_pTool->GetDocument();
+ if ( pDoc )
+ {
+ id = m_Items.Find( "properties" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ Panel *p;
+ p = m_pTool->GetProperties();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+
+ id = m_Items.Find( "picker" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ p = m_pTool->GetSequencePicker();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+
+ }
+ else
+ {
+ id = m_Items.Find( "properties" );
+ m_pMenu->SetItemEnabled( id, false );
+ id = m_Items.Find( "picker" );
+ m_pMenu->SetItemEnabled( id, false );
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+// The ActBusy menu
+//
+//-----------------------------------------------------------------------------
+class CActBusyMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CActBusyMenuButton, CToolMenuButton );
+public:
+ CActBusyMenuButton( CActBusyTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+
+private:
+ CActBusyTool *m_pTool;
+};
+
+CActBusyMenuButton::CActBusyMenuButton( CActBusyTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ m_pTool = parent;
+
+ AddMenuItem( "NewActBusy", "#ActBusyNewActBusy", new KeyValues( "Command", "command", "OnNewActBusy" ), pActionSignalTarget );
+ AddMenuItem( "DeleteActBusy", "#ActBusyDeleteActBusy", new KeyValues( "Command", "command", "OnDeleteActBusy" ), pActionSignalTarget );
+
+ SetMenu(m_pMenu);
+}
+
+void CActBusyMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ int id;
+
+ CActBusyDoc *pDoc = m_pTool->GetDocument();
+ if ( pDoc )
+ {
+ id = m_Items.Find( "NewActBusy" );
+ m_pMenu->SetItemEnabled( id, true );
+ id = m_Items.Find( "DeleteActBusy" );
+ m_pMenu->SetItemEnabled( id, true );
+ }
+ else
+ {
+ id = m_Items.Find( "NewActBusy" );
+ m_pMenu->SetItemEnabled( id, false );
+ id = m_Items.Find( "DeleteActBusy" );
+ m_pMenu->SetItemEnabled( id, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the menu bar
+//-----------------------------------------------------------------------------
+vgui::MenuBar *CActBusyTool::CreateMenuBar( CBaseToolSystem *pParent )
+{
+ m_pMenuBar = new CToolFileMenuBar( pParent, "ActBusyMenuBar" );
+
+ // Sets info in the menu bar
+ char title[ 64 ];
+ ComputeMenuBarTitle( title, sizeof( title ) );
+ m_pMenuBar->SetInfo( title );
+ m_pMenuBar->SetToolName( GetToolName() );
+ UpdateMenuBar();
+
+ // Add menu buttons
+ CToolMenuButton *pFileButton = CreateToolFileMenuButton( m_pMenuBar, "File", "&File", GetActionTarget(), this );
+ CToolMenuButton *pEditButton = CreateToolEditMenuButton( this, "Edit", "&Edit", GetActionTarget() );
+ CActBusyMenuButton *pActBusyButton = new CActBusyMenuButton( this, "ActBusy", "&ActBusy", GetActionTarget() );
+ CToolMenuButton *pSwitchButton = CreateToolSwitchMenuButton( m_pMenuBar, "Switcher", "&Tools", GetActionTarget() );
+ CActBusyViewMenuButton *pViewButton = new CActBusyViewMenuButton( this, "View", "&View", GetActionTarget() );
+
+ m_pMenuBar->AddButton( pFileButton );
+ m_pMenuBar->AddButton( pEditButton );
+ m_pMenuBar->AddButton( pActBusyButton );
+ m_pMenuBar->AddButton( pViewButton );
+ m_pMenuBar->AddButton( pSwitchButton );
+
+ return m_pMenuBar;
+}
+
+
+//-----------------------------------------------------------------------------
+// Updates the menu bar based on the current file
+//-----------------------------------------------------------------------------
+void CActBusyTool::UpdateMenuBar( )
+{
+ if ( !m_pDoc )
+ {
+ m_pMenuBar->SetFileName( "#ActBusyNoFile" );
+ return;
+ }
+
+ if ( m_pDoc->IsDirty() )
+ {
+ char sz[ 512 ];
+ Q_snprintf( sz, sizeof( sz ), "* %s", m_pDoc->GetFileName() );
+ m_pMenuBar->SetFileName( sz );
+ }
+ else
+ {
+ m_pMenuBar->SetFileName( m_pDoc->GetFileName() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from IFileMenuCallbacks
+//-----------------------------------------------------------------------------
+int CActBusyTool::GetFileMenuItemsEnabled( )
+{
+ int nFlags;
+ if ( !m_pDoc )
+ {
+ nFlags = FILE_NEW | FILE_OPEN | FILE_RECENT | FILE_CLEAR_RECENT | FILE_EXIT;
+ }
+ else
+ {
+ nFlags = FILE_ALL;
+ }
+
+ if ( m_RecentFiles.IsEmpty() )
+ {
+ nFlags &= ~(FILE_RECENT | FILE_CLEAR_RECENT);
+ }
+ return nFlags;
+}
+
+void CActBusyTool::AddRecentFilesToMenu( vgui::Menu *pMenu )
+{
+ m_RecentFiles.AddToMenu( pMenu, GetActionTarget(), "OnRecent" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the file name for perforce
+//-----------------------------------------------------------------------------
+bool CActBusyTool::GetPerforceFileName( char *pFileName, int nMaxLen )
+{
+ if ( !m_pDoc )
+ return false;
+ Q_strncpy( pFileName, m_pDoc->GetFileName(), nMaxLen );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get a new scheme to be applied to this tool
+//-----------------------------------------------------------------------------
+vgui::HScheme CActBusyTool::GetToolScheme()
+{
+ return vgui::scheme()->LoadSchemeFromFile( "Resource/BoxRocket.res", "BoxRocket" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates the action menu
+//-----------------------------------------------------------------------------
+vgui::Menu *CActBusyTool::CreateActionMenu( vgui::Panel *pParent )
+{
+ vgui::Menu *pActionMenu = new Menu( pParent, "ActionMenu" );
+ pActionMenu->AddMenuItem( "#ToolHide", new KeyValues( "Command", "command", "HideActionMenu" ), GetActionTarget() );
+ return pActionMenu;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+void CActBusyTool::OnExit()
+{
+ windowposmgr->SavePositions( "cfg/actbusy.txt", "ActBusy" );
+
+ // Throw up a "save" dialog?
+ enginetools->Command( "quit\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Handle commands from the action menu and other menus
+//-----------------------------------------------------------------------------
+void CActBusyTool::OnCommand( const char *cmd )
+{
+ if ( !V_stricmp( cmd, "HideActionMenu" ) )
+ {
+ if ( GetActionMenu() )
+ {
+ GetActionMenu()->SetVisible( false );
+ }
+ }
+ else if ( !V_stricmp( cmd, "OnNewActBusy" ) )
+ {
+ OnNewActBusy();
+ }
+ else if ( !V_stricmp( cmd, "OnDeleteActBusy" ) )
+ {
+ OnDeleteActBusy();
+ }
+ else if ( !V_stricmp( cmd, "OnToggleProperties" ) )
+ {
+ OnToggleProperties();
+ }
+ else if ( !V_stricmp( cmd, "OnToggleSequencePicker" ) )
+ {
+ OnToggleSequencePicker();
+ }
+ else if ( !V_stricmp( cmd, "OnDefaultLayout" ) )
+ {
+ OnDefaultLayout();
+ }
+ else if ( !V_stricmp( cmd, "OnUndo" ) )
+ {
+ OnUndo();
+ }
+ else if ( !V_stricmp( cmd, "OnRedo" ) )
+ {
+ OnRedo();
+ }
+ else if ( !V_stricmp( cmd, "OnDescribeUndo" ) )
+ {
+ OnDescribeUndo();
+ }
+ else if ( const char *pSuffix = StringAfterPrefix( cmd, "OnRecent" ) )
+ {
+ int idx = Q_atoi( pSuffix );
+ g_pActBusyTool->OpenFileFromHistory( idx, cmd );
+ }
+ else if( const char *pSuffixTool = StringAfterPrefix( cmd, "OnTool" ) )
+ {
+ int idx = Q_atoi( pSuffixTool );
+ enginetools->SwitchToTool( idx );
+ }
+ else
+ {
+ BaseClass::OnCommand( cmd );
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get notified when files are saved/loaded
+//-----------------------------------------------------------------------------
+void CActBusyTool::OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues )
+{
+ if ( bWroteFile )
+ {
+ OnMarkNotDirty();
+ }
+
+ if ( !pContextKeyValues )
+ return;
+
+ if ( state != FileOpenStateMachine::SUCCESSFUL )
+ return;
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnNew" ) )
+ {
+ PerformNew();
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnClose" ) )
+ {
+ OnCloseNoSave();
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnQuit" ) )
+ {
+ OnCloseNoSave();
+ vgui::ivgui()->PostMessage( GetVPanel(), new KeyValues( "OnExit" ), 0 );
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Called by SaveFile to allow clients to set up the save dialog
+//-----------------------------------------------------------------------------
+void CActBusyTool::SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ // Compute starting directory
+ char pStartingDir[ MAX_PATH ];
+ GetModSubdirectory( "scripts", pStartingDir, sizeof(pStartingDir) );
+
+ if ( bOpenFile )
+ {
+ pDialog->SetTitle( "Open ActBusy .TXT File", true );
+ }
+ else
+ {
+ pDialog->SetTitle( "Save ActBusy .TXT File As", true );
+ }
+
+ pDialog->SetStartDirectoryContext( "actbusy_session", pStartingDir );
+ pDialog->AddFilter( "*.txt", "ActBusy .TXT (*.txt)", true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called by SaveFile to allow clients to actually write the file out
+//-----------------------------------------------------------------------------
+bool CActBusyTool::OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ OnCloseNoSave();
+ return LoadDocument( pFileName );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called by SaveFile to allow clients to actually write the file out
+//-----------------------------------------------------------------------------
+bool CActBusyTool::OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ if ( !m_pDoc )
+ return true;
+
+ m_pDoc->SetFileName( pFileName );
+ m_pDoc->SaveToFile( );
+ UpdateMenuBar();
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Command handlers
+//-----------------------------------------------------------------------------
+void CActBusyTool::PerformNew()
+{
+ OnCloseNoSave();
+ NewDocument();
+}
+
+void CActBusyTool::OnNew()
+{
+ if ( m_pDoc )
+ {
+ if ( m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetFileName(), "actbusy", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnNew" ) );
+ return;
+ }
+ }
+
+ PerformNew();
+}
+
+void CActBusyTool::OnOpen()
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetFileName();
+ }
+
+ OpenFile( "actbusy", pSaveFileName, "actbusy", nFlags );
+}
+
+void CActBusyTool::OnSave()
+{
+ if ( m_pDoc )
+ {
+ SaveFile( m_pDoc->GetFileName(), "actbusy", FOSM_SHOW_PERFORCE_DIALOGS );
+ }
+}
+
+void CActBusyTool::OnSaveAs()
+{
+ if ( m_pDoc )
+ {
+ SaveFile( NULL, "actbusy", FOSM_SHOW_PERFORCE_DIALOGS );
+ }
+}
+
+void CActBusyTool::OnClose()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetFileName(), "actbusy", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnClose" ) );
+ return;
+ }
+
+ OnCloseNoSave();
+}
+
+void CActBusyTool::OnCloseNoSave()
+{
+ DestroyTools();
+
+ if ( m_pDoc )
+ {
+ CAppNotifyScopeGuard( "CActBusyTool::OnCloseNoSave", 0 );
+
+ delete m_pDoc;
+ m_pDoc = NULL;
+
+ if ( m_hProperties )
+ {
+ m_hProperties->SetObject( NULL );
+ }
+ }
+
+ UpdateMenuBar( );
+}
+
+void CActBusyTool::OnMarkNotDirty()
+{
+ if ( m_pDoc )
+ {
+ m_pDoc->SetDirty( false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Open a specific file
+//-----------------------------------------------------------------------------
+void CActBusyTool::OpenSpecificFile( const char *pFileName )
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc )
+ {
+ // File is already open
+ if ( !Q_stricmp( m_pDoc->GetFileName(), pFileName ) )
+ return;
+
+ if ( m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetFileName();
+ }
+ else
+ {
+ OnCloseNoSave();
+ }
+ }
+
+ OpenFile( pFileName, "actbusy", pSaveFileName, "actbusy", nFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the save document query dialog
+//-----------------------------------------------------------------------------
+void CActBusyTool::OpenFileFromHistory( int slot, const char *pCommand )
+{
+ const char *pFileName = m_RecentFiles.GetFile( slot );
+ if ( pFileName )
+ {
+ OpenSpecificFile( pFileName );
+ }
+}
+
+bool CActBusyTool::CanQuit()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ // Show Save changes Yes/No/Cancel and re-quit if hit yes/no
+ SaveFile( m_pDoc->GetFileName(), "actbusy", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnQuit" ) );
+ return false;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Various command handlers related to the Edit menu
+//-----------------------------------------------------------------------------
+void CActBusyTool::OnUndo()
+{
+ CDisableUndoScopeGuard guard;
+ g_pDataModel->Undo();
+}
+
+void CActBusyTool::OnRedo()
+{
+ CDisableUndoScopeGuard guard;
+ g_pDataModel->Redo();
+}
+
+void CActBusyTool::OnDescribeUndo()
+{
+ CUtlVector< UndoInfo_t > list;
+ g_pDataModel->GetUndoInfo( list );
+
+ Msg( "%i operations in stack\n", list.Count() );
+
+ for ( int i = list.Count() - 1; i >= 0; --i )
+ {
+ UndoInfo_t& entry = list[ i ];
+ if ( entry.terminator )
+ {
+ Msg( "[ '%s' ] - %i operations\n", entry.undo, entry.numoperations );
+ }
+
+ Msg( " +%s\n", entry.desc );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Commands related to the actbusy menu
+//-----------------------------------------------------------------------------
+void CActBusyTool::OnNewActBusy()
+{
+ if ( m_pDoc )
+ {
+ m_pDoc->CreateActBusy();
+ }
+}
+
+void CActBusyTool::OnDeleteActBusy()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from IActBusyDocCallback
+//-----------------------------------------------------------------------------
+void CActBusyTool::OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ UpdateMenuBar();
+ if ( ( nNotifySource != NOTIFY_SOURCE_PROPERTIES_TREE ) && m_hProperties.Get() )
+ {
+ m_hProperties->Refresh();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+// Output : CActBusyDoc
+//-----------------------------------------------------------------------------
+CActBusyDoc *CActBusyTool::GetDocument()
+{
+ return m_pDoc;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+// Output : virtual CBasePropertiesContainer
+//-----------------------------------------------------------------------------
+CBasePropertiesContainer *CActBusyTool::GetProperties()
+{
+ return m_hProperties.Get();
+}
+
+CMDLSequencePicker *CActBusyTool::GetSequencePicker()
+{
+ return m_hMDLSequencePicker.Get();
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the tools
+//-----------------------------------------------------------------------------
+void CActBusyTool::InitTools()
+{
+ ShowElementProperties();
+
+ // FIXME: There are no tool windows here; how should this work?
+ // These panels are saved
+ windowposmgr->RegisterPanel( "picker", m_hMDLSequencePicker, false );
+ windowposmgr->RegisterPanel( "properties", m_hProperties, false );
+
+ if ( !windowposmgr->LoadPositions( "cfg/actbusy.txt", this, &m_ToolWindowFactory, "ActBusy" ) )
+ {
+ OnDefaultLayout();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads up a new document
+//-----------------------------------------------------------------------------
+bool CActBusyTool::LoadDocument( const char *pDocName )
+{
+ Assert( !m_pDoc );
+
+ DestroyTools();
+
+ m_pDoc = new CActBusyDoc( this );
+ if ( !m_pDoc->LoadFromFile( pDocName ) )
+ {
+ delete m_pDoc;
+ m_pDoc = NULL;
+ Warning( "Fatal error loading '%s'\n", pDocName );
+ return false;
+ }
+
+// ShowMiniViewport( false );
+
+ CreateTools( m_pDoc );
+
+ m_RecentFiles.Add( pDocName, "actbusy" );
+ UpdateMenuBar( );
+
+ InitTools();
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads up a new document
+//-----------------------------------------------------------------------------
+void CActBusyTool::NewDocument( )
+{
+ Assert( !m_pDoc );
+
+ m_pDoc = new CActBusyDoc( this );
+ m_pDoc->CreateNew( );
+
+// ShowMiniViewport( false );
+
+ CreateTools( m_pDoc );
+ UpdateMenuBar( );
+ InitTools();
+}
+
+
+//-----------------------------------------------------------------------------
+// Shows element properties
+//-----------------------------------------------------------------------------
+void CActBusyTool::ShowElementProperties( )
+{
+ if ( !m_pDoc )
+ return;
+
+ if ( !m_pDoc->GetRootObject() )
+ return;
+
+ // It should already exist
+ Assert( m_hProperties.Get() );
+ if ( m_hProperties.Get() )
+ {
+ m_hProperties->SetObject( m_pDoc->GetRootObject() );
+ }
+}
+
+void CActBusyTool::DestroyTools()
+{
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+
+ UnregisterAllToolWindows();
+
+ if ( m_hProperties.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hProperties.Get() );
+ delete m_hProperties.Get();
+ m_hProperties = NULL;
+ }
+ if ( m_hMDLSequencePicker.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hMDLSequencePicker.Get() );
+ delete m_hMDLSequencePicker.Get();
+ m_hMDLSequencePicker = NULL;
+ }
+}
+
+void CActBusyTool::CreateTools( CActBusyDoc *doc )
+{
+ if ( !m_hProperties.Get() )
+ {
+ m_hProperties = new CBasePropertiesContainer( NULL, m_pDoc, g_pEditorTypeDict );
+ }
+ if ( !m_hMDLSequencePicker.Get() )
+ {
+ m_hMDLSequencePicker = new CMDLSequencePicker( NULL );
+ SETUP_PANEL( m_hMDLSequencePicker.Get() );
+ m_hMDLSequencePicker->Activate();
+ }
+
+ RegisterToolWindow( m_hProperties );
+ RegisterToolWindow( m_hMDLSequencePicker );
+}
+
+void CActBusyTool::ShowToolWindow( Panel *tool, const char *toolName, bool visible )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL && visible )
+ {
+ m_ToolWindowFactory.InstanceToolWindow( this, false, tool, toolName, false );
+ }
+ else if ( !visible )
+ {
+ ToolWindow *tw = dynamic_cast< ToolWindow * >( tool->GetParent()->GetParent() );
+ Assert( tw );
+ tw->RemovePage( tool );
+ }
+}
+
+void CActBusyTool::ToggleToolWindow( Panel *tool, const char *toolName )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL )
+ {
+ ShowToolWindow( tool, toolName, true );
+ }
+ else
+ {
+ ShowToolWindow( tool, toolName, false );
+ }
+}
+
+void CActBusyTool::DestroyToolContainers()
+{
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+}
+
+void CActBusyTool::OnDefaultLayout()
+{
+ int y = m_pMenuBar->GetTall();
+
+ int usew, useh;
+ GetSize( usew, useh );
+
+ DestroyToolContainers();
+
+ Assert( ToolWindow::GetToolWindowCount() == 0 );
+
+ CBasePropertiesContainer *properties = GetProperties();
+ CMDLSequencePicker *picker = GetSequencePicker();
+
+ // Need three containers
+ ToolWindow *propertyWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, properties, "#ActBusyProperties", false );
+ ToolWindow *pickerWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, picker, "#ActBusyViewSequencePicker", false );
+
+ int halfScreen = usew / 2;
+ int bottom = useh - y;
+
+ propertyWindow->SetBounds( 0, y, halfScreen, bottom );
+ pickerWindow->SetBounds( halfScreen, y, halfScreen, bottom );
+}
+
+void CActBusyTool::OnToggleProperties()
+{
+ ToggleToolWindow( m_hProperties.Get(), "#ActBusyProperties" );
+}
+
+void CActBusyTool::OnToggleSequencePicker()
+{
+ ToggleToolWindow( m_hMDLSequencePicker.Get(), "#ActBusyViewSequencePicker" );
+}
+
+const char *CActBusyTool::GetLogoTextureName()
+{
+ return "vgui/tools/actbusy/actbusy_logo";
+} \ No newline at end of file
diff --git a/tools/actbusy/actbusytool.h b/tools/actbusy/actbusytool.h
new file mode 100644
index 0000000..4f94782
--- /dev/null
+++ b/tools/actbusy/actbusytool.h
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Act busy tool; main UI smarts class
+//
+//=============================================================================
+
+#ifndef ACTBUSYTOOL_H
+#define ACTBUSYTOOL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CDmeEditorTypeDictionary;
+
+
+//-----------------------------------------------------------------------------
+// Singleton interfaces
+//-----------------------------------------------------------------------------
+extern CDmeEditorTypeDictionary *g_pEditorTypeDict;
+
+
+//-----------------------------------------------------------------------------
+// Allows the doc to call back into the act busy tool
+//-----------------------------------------------------------------------------
+class IActBusyDocCallback
+{
+public:
+ // Called by the doc when the data changes
+ virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags ) = 0;
+};
+
+
+#endif // ACTBUSYTOOL_H
diff --git a/tools/commedit/commedit.vpc b/tools/commedit/commedit.vpc
new file mode 100644
index 0000000..1545cb3
--- /dev/null
+++ b/tools/commedit/commedit.vpc
@@ -0,0 +1,64 @@
+//-----------------------------------------------------------------------------
+// COMMEDIT.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin\tools"
+
+$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE,.\,..\common,$SRCDIR\game\shared"
+ $PreprocessorDefinitions "$BASE;COMMEDIT_EXPORTS"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "$BASE Psapi.lib"
+ }
+}
+
+$Project "Commedit"
+{
+ $Folder "Source Files"
+ {
+ $File "commeditdoc.cpp"
+ $File "commedittool.cpp"
+ $File "commentarynodebrowserpanel.cpp"
+ $File "commentarypropertiespanel.cpp"
+ $File "dmecommentarynodeentity.cpp"
+ $File "$SRCDIR\public\interpolatortypes.cpp"
+ $File "$SRCDIR\public\registry.cpp"
+ $File "$SRCDIR\public\vgui_controls\vgui_controls.cpp"
+ }
+
+ $Folder "Header Files"
+ {
+ $File "commeditdoc.h"
+ $File "commedittool.h"
+ $File "commentarynodebrowserpanel.h"
+ $File "commentarypropertiespanel.h"
+ $File "dmecommentarynodeentity.h"
+ $File "$SRCDIR\public\mathlib\mathlib.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib datamodel
+ $Lib dme_controls
+ $Lib dmserializers
+ $Lib mathlib
+ $Lib matsys_controls
+ $Lib movieobjects
+ $Lib sfmobjects
+ $Lib tier2
+ $Lib tier3
+ $Lib toolutils
+ $Lib vgui_controls
+ }
+}
diff --git a/tools/commedit/commeditdoc.cpp b/tools/commedit/commeditdoc.cpp
new file mode 100644
index 0000000..6ebd5fd
--- /dev/null
+++ b/tools/commedit/commeditdoc.cpp
@@ -0,0 +1,443 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "commeditdoc.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "toolutils/enginetools_int.h"
+#include "filesystem.h"
+#include "commedittool.h"
+#include "toolframework/ienginetool.h"
+#include "dmecommentarynodeentity.h"
+#include "datamodel/idatamodel.h"
+#include "toolutils/attributeelementchoicelist.h"
+#include "commentarynodebrowserpanel.h"
+#include "vgui_controls/messagebox.h"
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CCommEditDoc::CCommEditDoc( ICommEditDocCallback *pCallback ) : m_pCallback( pCallback )
+{
+ m_hRoot = NULL;
+ m_pTXTFileName[0] = 0;
+ m_bDirty = false;
+ g_pDataModel->InstallNotificationCallback( this );
+}
+
+CCommEditDoc::~CCommEditDoc()
+{
+ g_pDataModel->RemoveNotificationCallback( this );
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from INotifyUI
+//-----------------------------------------------------------------------------
+void CCommEditDoc::NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ OnDataChanged( pReason, nNotifySource, nNotifyFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the file name
+//-----------------------------------------------------------------------------
+const char *CCommEditDoc::GetTXTFileName()
+{
+ return m_pTXTFileName;
+}
+
+void CCommEditDoc::SetTXTFileName( const char *pFileName )
+{
+ Q_strncpy( m_pTXTFileName, pFileName, sizeof( m_pTXTFileName ) );
+ Q_FixSlashes( m_pTXTFileName );
+ SetDirty( true );
+}
+
+//-----------------------------------------------------------------------------
+// Dirty bits
+//-----------------------------------------------------------------------------
+void CCommEditDoc::SetDirty( bool bDirty )
+{
+ m_bDirty = bDirty;
+}
+
+bool CCommEditDoc::IsDirty() const
+{
+ return m_bDirty;
+}
+
+
+//-----------------------------------------------------------------------------
+// Handles creation of the right element for a keyvalue
+//-----------------------------------------------------------------------------
+class CElementForKeyValueCallback : public IElementForKeyValueCallback
+{
+public:
+ const char *GetElementForKeyValue( const char *pszKeyName, int iNestingLevel )
+ {
+ if ( iNestingLevel == 1 && !Q_strncmp(pszKeyName, "entity", 6) )
+ return "DmeCommentaryNodeEntity";
+
+ return NULL;
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Saves/loads from file
+//-----------------------------------------------------------------------------
+bool CCommEditDoc::LoadFromFile( const char *pFileName )
+{
+ Assert( !m_hRoot.Get() );
+
+ CAppDisableUndoScopeGuard guard( "CCommEditDoc::LoadFromFile", 0 );
+ SetDirty( false );
+
+ if ( !pFileName[0] )
+ return false;
+
+ char mapname[ 256 ];
+
+ // Compute the map name
+ const char *pMaps = Q_stristr( pFileName, "\\maps\\" );
+ if ( !pMaps )
+ return false;
+
+ // Build map name
+ //int nNameLen = (int)( (size_t)pComm - (size_t)pMaps ) - 5;
+ Q_StripExtension( pFileName, mapname, sizeof(mapname) );
+ char *pszFileName = (char*)Q_UnqualifiedFileName(mapname);
+
+ // Set the txt file name.
+ // If we loaded an existing commentary file, keep the same filename.
+ // If we loaded a .bsp, change the name & the extension.
+ if ( !V_stricmp( Q_GetFileExtension( pFileName ), "bsp" ) )
+ {
+ const char *pCommentaryAppend = "_commentary.txt";
+ Q_StripExtension( pFileName, m_pTXTFileName, sizeof(m_pTXTFileName)- strlen(pCommentaryAppend) - 1 );
+ Q_strcat( m_pTXTFileName, pCommentaryAppend, sizeof( m_pTXTFileName ) );
+
+ if ( g_pFileSystem->FileExists( m_pTXTFileName ) )
+ {
+ char pBuf[1024];
+ Q_snprintf( pBuf, sizeof(pBuf), "File %s already exists!\n", m_pTXTFileName );
+ m_pTXTFileName[0] = 0;
+ vgui::MessageBox *pMessageBox = new vgui::MessageBox( "Unable to overwrite file!\n", pBuf, g_pCommEditTool );
+ pMessageBox->DoModal( );
+ return false;
+ }
+
+ DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( m_pTXTFileName );
+
+ m_hRoot = CreateElement<CDmElement>( "root", fileid );
+ CDmrElementArray<> subkeys( m_hRoot->AddAttribute( "subkeys", AT_ELEMENT_ARRAY ) );
+ CDmElement *pRoot2 = CreateElement<CDmElement>( "Entities", fileid );
+ pRoot2->AddAttribute( "subkeys", AT_ELEMENT_ARRAY );
+ subkeys.AddToTail( pRoot2 );
+ g_pDataModel->SetFileRoot( fileid, m_hRoot );
+ }
+ else
+ {
+ char *pComm = Q_stristr( pszFileName, "_commentary" );
+ if ( !pComm )
+ {
+ char pBuf[1024];
+ Q_snprintf( pBuf, sizeof(pBuf), "File %s is not a commentary file!\nThe file name must end in _commentary.txt.\n", m_pTXTFileName );
+ m_pTXTFileName[0] = 0;
+ vgui::MessageBox *pMessageBox = new vgui::MessageBox( "Bad file name!\n", pBuf, g_pCommEditTool );
+ pMessageBox->DoModal( );
+ return false;
+ }
+
+ // Clip off the "_commentary" at the end of the filename
+ *pComm = '\0';
+
+ // This is not undoable
+ CDisableUndoScopeGuard guardFile;
+
+ CDmElement *pTXT = NULL;
+
+ CElementForKeyValueCallback KeyValuesCallback;
+ g_pDataModel->SetKeyValuesElementCallback( &KeyValuesCallback );
+ DmFileId_t fileid = g_pDataModel->RestoreFromFile( pFileName, NULL, "keyvalues", &pTXT );
+ g_pDataModel->SetKeyValuesElementCallback( NULL );
+
+ if ( fileid == DMFILEID_INVALID )
+ {
+ m_pTXTFileName[0] = 0;
+ return false;
+ }
+
+ SetTXTFileName( pFileName );
+ m_hRoot = pTXT;
+ }
+
+ guard.Release();
+ SetDirty( false );
+
+ char cmd[ 256 ];
+ Q_snprintf( cmd, sizeof( cmd ), "disconnect; map %s\n", pszFileName );
+ enginetools->Command( cmd );
+ enginetools->Execute( );
+
+ return true;
+}
+
+void CCommEditDoc::SaveToFile( )
+{
+ if ( m_hRoot.Get() && m_pTXTFileName && m_pTXTFileName[0] )
+ {
+ g_pDataModel->SaveToFile( m_pTXTFileName, NULL, "keyvalues", "keyvalues", m_hRoot );
+ }
+
+ SetDirty( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the root object
+//-----------------------------------------------------------------------------
+CDmElement *CCommEditDoc::GetRootObject()
+{
+ return m_hRoot;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the entity list
+//-----------------------------------------------------------------------------
+CDmAttribute *CCommEditDoc::GetEntityList()
+{
+ CDmrElementArray<> mainKeys( m_hRoot, "subkeys" );
+ if ( !mainKeys.IsValid() || mainKeys.Count() == 0 )
+ return NULL;
+ CDmeHandle<CDmElement> hEntityList;
+ hEntityList = mainKeys[ 0 ];
+ return hEntityList ? hEntityList->GetAttribute( "subkeys", AT_ELEMENT_ARRAY ) : NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommEditDoc::AddNewInfoTarget( const Vector &vecOrigin, const QAngle &angAngles )
+{
+ CDmrCommentaryNodeEntityList entities( GetEntityList() );
+ if ( !entities.IsValid() )
+ return;
+
+ CDmeCommentaryNodeEntity *pTarget;
+ {
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Add Info Target", "Add Info Target" );
+
+ pTarget = CreateElement<CDmeCommentaryNodeEntity>( "target", entities.GetOwner()->GetFileId() );
+ pTarget->SetName( "entity" );
+ pTarget->SetValue( "classname", "info_target" );
+ pTarget->SetRenderOrigin( vecOrigin );
+ pTarget->SetRenderAngles( angAngles );
+
+ entities.AddToTail( pTarget );
+ pTarget->MarkDirty();
+ pTarget->DrawInEngine( true );
+ }
+
+ g_pCommEditTool->GetCommentaryNodeBrowser()->SelectNode( pTarget );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommEditDoc::AddNewInfoTarget( void )
+{
+ Vector vecOrigin;
+ QAngle angAngles;
+ float flFov;
+ clienttools->GetLocalPlayerEyePosition( vecOrigin, angAngles, flFov );
+ AddNewInfoTarget( vecOrigin, vec3_angle );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommEditDoc::AddNewCommentaryNode( const Vector &vecOrigin, const QAngle &angAngles )
+{
+ CDmrCommentaryNodeEntityList entities = GetEntityList();
+
+ CDmeCommentaryNodeEntity *pNode;
+ {
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Add Commentary Node", "Add Commentary Node" );
+
+ pNode = CreateElement<CDmeCommentaryNodeEntity>( "node", entities.GetOwner()->GetFileId() );
+ pNode->SetName( "entity" );
+ pNode->SetValue( "classname", "point_commentary_node" );
+ pNode->SetRenderOrigin( vecOrigin );
+ pNode->SetRenderAngles( angAngles );
+ pNode->SetValue<CUtlString>( "precommands", "" );
+ pNode->SetValue<CUtlString>( "postcommands", "" );
+ pNode->SetValue<CUtlString>( "commentaryfile", "" );
+ pNode->SetValue<CUtlString>( "viewtarget", "" );
+ pNode->SetValue<CUtlString>( "viewposition", "" );
+ pNode->SetValue<int>( "prevent_movement", 0 );
+ pNode->SetValue<CUtlString>( "speakers", "" );
+ pNode->SetValue<CUtlString>( "synopsis", "" );
+
+ entities.AddToTail( pNode );
+ pNode->MarkDirty();
+ pNode->DrawInEngine( true );
+ }
+
+ g_pCommEditTool->GetCommentaryNodeBrowser()->SelectNode( pNode );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommEditDoc::AddNewCommentaryNode( void )
+{
+ Vector vecOrigin;
+ QAngle angAngles;
+ float flFov;
+ clienttools->GetLocalPlayerEyePosition( vecOrigin, angAngles, flFov );
+ AddNewCommentaryNode( vecOrigin, vec3_angle );
+}
+
+
+//-----------------------------------------------------------------------------
+// Deletes a commentary node
+//-----------------------------------------------------------------------------
+void CCommEditDoc::DeleteCommentaryNode( CDmElement *pRemoveNode )
+{
+ CDmrCommentaryNodeEntityList entities = GetEntityList();
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ if ( pRemoveNode == entities[i] )
+ {
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Delete Commentary Node", "Delete Commentary Node" );
+ CDmeCommentaryNodeEntity *pNode = entities[ i ];
+ pNode->DrawInEngine( false );
+ entities.FastRemove( i );
+ return;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &vecOrigin -
+// &angAbsAngles -
+// Output : CDmeCommentaryNodeEntity
+//-----------------------------------------------------------------------------
+CDmeCommentaryNodeEntity *CCommEditDoc::GetCommentaryNodeForLocation( Vector &vecOrigin, QAngle &angAbsAngles )
+{
+ CDmrCommentaryNodeEntityList entities = GetEntityList();
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeCommentaryNodeEntity *pNode = entities[ i ];
+ if ( !pNode )
+ continue;
+
+ Vector &vecAngles = *(Vector*)(&pNode->GetRenderAngles());
+ if ( pNode->GetRenderOrigin().DistTo( vecOrigin ) < 1e-3 && vecAngles.DistTo( *(Vector*)&angAbsAngles ) < 1e-1 )
+ return pNode;
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Populate string choice lists
+//-----------------------------------------------------------------------------
+bool CCommEditDoc::GetStringChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, StringChoiceList_t &list )
+{
+ if ( !Q_stricmp( pChoiceListType, "info_targets" ) )
+ {
+ CDmrCommentaryNodeEntityList entities = GetEntityList();
+
+ StringChoice_t sChoice;
+ sChoice.m_pValue = "";
+ sChoice.m_pChoiceString = "";
+ list.AddToTail( sChoice );
+
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeCommentaryNodeEntity *pNode = entities[ i ];
+ if ( !pNode )
+ continue;
+
+ if ( !V_stricmp( pNode->GetClassName(), "info_target" ) )
+ {
+ sChoice.m_pValue = pNode->GetTargetName();
+ sChoice.m_pChoiceString = pNode->GetTargetName();
+ list.AddToTail( sChoice );
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Populate element choice lists
+//-----------------------------------------------------------------------------
+bool CCommEditDoc::GetElementChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, ElementChoiceList_t &list )
+{
+ if ( !Q_stricmp( pChoiceListType, "allelements" ) )
+ {
+ AddElementsRecursively( m_hRoot, list );
+ return true;
+ }
+
+ if ( !Q_stricmp( pChoiceListType, "info_targets" ) )
+ {
+ CDmrCommentaryNodeEntityList entities = GetEntityList();
+
+ bool bFound = false;
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeCommentaryNodeEntity *pNode = entities[ i ];
+ if ( pNode && !V_stricmp( pNode->GetClassName(), "info_target" ) )
+ {
+ bFound = true;
+ ElementChoice_t sChoice;
+ sChoice.m_pValue = pNode;
+ sChoice.m_pChoiceString = pNode->GetTargetName();
+ list.AddToTail( sChoice );
+ }
+ }
+ return bFound;
+ }
+
+ // by default, try to treat the choice list type as a Dme element type
+ AddElementsRecursively( m_hRoot, list, pChoiceListType );
+
+ return list.Count() > 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when data changes
+//-----------------------------------------------------------------------------
+void CCommEditDoc::OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ SetDirty( nNotifyFlags & NOTIFY_SETDIRTYFLAG ? true : false );
+ m_pCallback->OnDocChanged( pReason, nNotifySource, nNotifyFlags );
+}
+
+
diff --git a/tools/commedit/commeditdoc.h b/tools/commedit/commeditdoc.h
new file mode 100644
index 0000000..0c51b62
--- /dev/null
+++ b/tools/commedit/commeditdoc.h
@@ -0,0 +1,92 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef COMMEDITDOC_H
+#define COMMEDITDOC_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "dme_controls/inotifyui.h"
+#include "datamodel/dmehandle.h"
+#include "datamodel/dmelement.h"
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class ICommEditDocCallback;
+class CCommEditDoc;
+class CDmeCommentaryNodeEntity;
+
+typedef CDmrElementArray<CDmeCommentaryNodeEntity> CDmrCommentaryNodeEntityList;
+
+
+//-----------------------------------------------------------------------------
+// Contains all editable state
+//-----------------------------------------------------------------------------
+class CCommEditDoc : public IDmNotify
+{
+public:
+ CCommEditDoc( ICommEditDocCallback *pCallback );
+ ~CCommEditDoc();
+
+ // Inherited from INotifyUI
+ virtual void NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Sets/Gets the file name
+ const char *GetTXTFileName();
+ void SetTXTFileName( const char *pFileName );
+
+ // Dirty bits (has it changed since the last time it was saved?)
+ void SetDirty( bool bDirty );
+ bool IsDirty() const;
+
+ // Saves/loads from file
+ bool LoadFromFile( const char *pFileName );
+ void SaveToFile( );
+
+ // Returns the root object
+ CDmElement *GetRootObject();
+
+ // Called when data changes (see INotifyUI for flags)
+ void OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Returns the entity list
+ CDmAttribute *GetEntityList();
+
+ // Adds a new info_target
+ void AddNewInfoTarget( void );
+ void AddNewInfoTarget( const Vector &vecOrigin, const QAngle &angAngles );
+
+ // Adds a new commentary node
+ void AddNewCommentaryNode( void );
+ void AddNewCommentaryNode( const Vector &vecOrigin, const QAngle &angAngles );
+
+ // Deletes a commentary node
+ void DeleteCommentaryNode( CDmElement *pNode );
+
+ // Returns the commentary node at the specified location
+ CDmeCommentaryNodeEntity *GetCommentaryNodeForLocation( Vector &vecOrigin, QAngle &angAbsAngles );
+
+ // For element choice lists. Return false if it's an unknown choice list type
+ virtual bool GetStringChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, StringChoiceList_t &list );
+ virtual bool GetElementChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, ElementChoiceList_t &list );
+
+private:
+ ICommEditDocCallback *m_pCallback;
+ CDmeHandle< CDmElement > m_hRoot;
+ char m_pTXTFileName[512];
+ bool m_bDirty;
+};
+
+
+#endif // COMMEDITDOC_H
diff --git a/tools/commedit/commedittool.cpp b/tools/commedit/commedittool.cpp
new file mode 100644
index 0000000..299d770
--- /dev/null
+++ b/tools/commedit/commedittool.cpp
@@ -0,0 +1,1284 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core Movie Maker UI API
+//
+//=============================================================================
+
+#include "commedittool.h"
+#include "vgui_controls/Menu.h"
+#include "tier1/KeyValues.h"
+#include "vgui/IInput.h"
+#include "vgui/KeyCode.h"
+#include "vgui_controls/FileOpenDialog.h"
+#include "vgui_controls/PropertySheet.h"
+#include "filesystem.h"
+#include "vgui/ilocalize.h"
+#include "dme_controls/elementpropertiestree.h"
+#include "tier0/icommandline.h"
+#include "materialsystem/imaterialsystem.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "commeditdoc.h"
+#include "commentarynodebrowserpanel.h"
+#include "commentarypropertiespanel.h"
+#include "dme_controls/AttributeStringChoicePanel.h"
+#include "tier2/fileutils.h"
+#include "tier3/tier3.h"
+#include "vgui/ivgui.h"
+#include "toolutils/ConsolePage.h"
+
+
+using namespace vgui;
+
+
+enum
+{
+ FILEOPEN_NEW_BSP,
+ FILEOPEN_EXISTING_TXT,
+};
+
+
+const char *GetVGuiControlsModuleName()
+{
+ return "CommEditTool";
+}
+
+//-----------------------------------------------------------------------------
+// Connect, disconnect
+//-----------------------------------------------------------------------------
+bool ConnectTools( CreateInterfaceFn factory )
+{
+ return (materials != NULL) && (g_pMatSystemSurface != NULL) && (g_pMDLCache != NULL) && (studiorender != NULL) && (g_pMaterialSystemHardwareConfig != NULL);
+}
+
+void DisconnectTools( )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Singleton
+//-----------------------------------------------------------------------------
+CCommEditTool *g_pCommEditTool = NULL;
+
+void CreateTools()
+{
+ g_pCommEditTool = new CCommEditTool();
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CCommEditTool::CCommEditTool()
+{
+ m_bInNodeDropMode = false;
+ m_pMenuBar = NULL;
+ m_pDoc = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Init, shutdown
+//-----------------------------------------------------------------------------
+bool CCommEditTool::Init( )
+{
+ m_pDoc = NULL;
+ m_RecentFiles.LoadFromRegistry( GetRegistryName() );
+
+ // NOTE: This has to happen before BaseClass::Init
+ g_pVGuiLocalize->AddFile( "resource/toolcommedit_%language%.txt" );
+
+ if ( !BaseClass::Init( ) )
+ return false;
+
+ {
+ m_hPreviewNode = CreateElement<CDmeCommentaryNodeEntity>( "preview node", DMFILEID_INVALID );
+ m_hPreviewNode->SetValue( "classname", "point_commentary_node" );
+ m_hPreviewTarget = CreateElement<CDmeCommentaryNodeEntity>( "preview target", DMFILEID_INVALID );
+ m_hPreviewTarget->SetValue( "classname", "info_target" );
+ }
+
+ return true;
+}
+
+void CCommEditTool::Shutdown()
+{
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+
+ g_pDataModel->DestroyElement( m_hPreviewNode );
+ g_pDataModel->DestroyElement( m_hPreviewTarget );
+
+ BaseClass::Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// returns the document
+//-----------------------------------------------------------------------------
+inline CCommEditDoc *CCommEditTool::GetDocument()
+{
+ return m_pDoc;
+}
+
+
+//-----------------------------------------------------------------------------
+// Tool activation/deactivation
+//-----------------------------------------------------------------------------
+void CCommEditTool::OnToolActivate()
+{
+ BaseClass::OnToolActivate();
+
+ enginetools->Command( "commentary 1\n" );
+}
+
+void CCommEditTool::OnToolDeactivate()
+{
+ BaseClass::OnToolDeactivate();
+
+ enginetools->Command( "commentary 0\n" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Enter mode where we preview dropping nodes
+//-----------------------------------------------------------------------------
+void CCommEditTool::EnterNodeDropMode()
+{
+ // Can only do it in editor mode
+ if ( IsGameInputEnabled() )
+ return;
+
+ m_bInNodeDropMode = true;
+ m_bDroppingCommentaryNodes = true;
+ SetMode( true, IsFullscreen() );
+ {
+ CDisableUndoScopeGuard guard;
+ m_hPreviewNode->DrawInEngine( true );
+ }
+ SetMiniViewportText( "Left Click To Place Commentary\nRight Click To Toggle Modes\nESC to exit" );
+ enginetools->Command( "noclip\n" );
+}
+
+void CCommEditTool::LeaveNodeDropMode()
+{
+ Assert( m_bInNodeDropMode );
+
+ m_bInNodeDropMode = false;
+ SetMode( false, IsFullscreen() );
+ {
+ CDisableUndoScopeGuard guard;
+ m_hPreviewNode->DrawInEngine( false );
+ m_hPreviewTarget->DrawInEngine( false );
+ }
+ SetMiniViewportText( NULL );
+ enginetools->Command( "noclip\n" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the position of the preview object
+//-----------------------------------------------------------------------------
+void CCommEditTool::GetPlacementInfo( Vector &vecOrigin, QAngle &angAngles )
+{
+ // Places the placement objects
+ float flFov;
+ clienttools->GetLocalPlayerEyePosition( vecOrigin, angAngles, flFov );
+
+ Vector vecForward;
+ AngleVectors( angAngles, &vecForward );
+ VectorMA( vecOrigin, 40.0f, vecForward, vecOrigin );
+
+ // Eliminate pitch
+ angAngles.x = 0.0f;
+}
+
+
+//-----------------------------------------------------------------------------
+// Place the preview object before rendering
+//-----------------------------------------------------------------------------
+void CCommEditTool::ClientPreRender()
+{
+ BaseClass::ClientPreRender();
+ if ( !m_bInNodeDropMode )
+ return;
+
+ // Places the placement objects
+ Vector vecOrigin;
+ QAngle angAngles;
+ GetPlacementInfo( vecOrigin, angAngles );
+
+ CDisableUndoScopeGuard guard;
+ m_hPreviewNode->SetRenderOrigin( vecOrigin );
+ m_hPreviewNode->SetRenderAngles( angAngles );
+
+ m_hPreviewTarget->SetRenderOrigin( vecOrigin );
+ m_hPreviewTarget->SetRenderAngles( angAngles );
+}
+
+
+//-----------------------------------------------------------------------------
+// Let tool override key events (ie ESC and ~)
+//-----------------------------------------------------------------------------
+bool CCommEditTool::TrapKey( ButtonCode_t key, bool down )
+{
+ // Don't hook keyboard if not topmost
+ if ( !IsActiveTool() )
+ return false; // didn't trap, continue processing
+
+ if ( !m_bInNodeDropMode )
+ {
+ if ( !IsGameInputEnabled() && !IsFullscreen() && ( key == KEY_BACKQUOTE ) && down )
+ {
+ BringConsoleToFront();
+ return true;
+ }
+ return BaseClass::TrapKey( key, down );
+ }
+
+ if ( !down )
+ return false;
+
+ if ( key == KEY_ESCAPE )
+ {
+ LeaveNodeDropMode();
+ return true; // trapping this key, stop processing
+ }
+
+ if ( key == MOUSE_LEFT )
+ {
+ Vector vecOrigin;
+ QAngle angAngles;
+ GetPlacementInfo( vecOrigin, angAngles );
+ if ( m_bDroppingCommentaryNodes )
+ {
+ m_pDoc->AddNewCommentaryNode( vecOrigin, angAngles );
+ }
+ else
+ {
+ m_pDoc->AddNewInfoTarget( vecOrigin, angAngles );
+ }
+ return true; // trapping this key, stop processing
+ }
+
+ if ( key == MOUSE_RIGHT )
+ {
+ m_bDroppingCommentaryNodes = !m_bDroppingCommentaryNodes;
+ if ( m_bDroppingCommentaryNodes )
+ {
+ SetMiniViewportText( "Left Click To Place Commentary\nRight Click To Toggle Modes\nESC to exit" );
+ }
+ else
+ {
+ SetMiniViewportText( "Left Click To Place Target\nRight Click To Toggle Modes\nESC to exit" );
+ }
+ CDisableUndoScopeGuard guard;
+ m_hPreviewNode->DrawInEngine( m_bDroppingCommentaryNodes );
+ m_hPreviewTarget->DrawInEngine( !m_bDroppingCommentaryNodes );
+ return true; // trapping this key, stop processing
+ }
+
+ return false; // didn't trap, continue processing
+}
+
+
+//-----------------------------------------------------------------------------
+// Used to hook DME VMF entities into the render lists
+//-----------------------------------------------------------------------------
+void CCommEditTool::DrawCommentaryNodeEntitiesInEngine( bool bDrawInEngine )
+{
+ if ( !m_pDoc )
+ return;
+
+ CDmrCommentaryNodeEntityList entities = m_pDoc->GetEntityList();
+ if ( !entities.IsValid() )
+ return;
+
+ CDisableUndoScopeGuard guard;
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeCommentaryNodeEntity *pEntity = entities[i];
+ Assert( pEntity );
+ if ( pEntity )
+ {
+ pEntity->DrawInEngine( bDrawInEngine );
+ }
+ }
+}
+
+void CCommEditTool::ClientLevelInitPostEntity()
+{
+ BaseClass::ClientLevelInitPostEntity();
+ DrawCommentaryNodeEntitiesInEngine( true );
+
+ AttachAllEngineEntities();
+}
+
+void CCommEditTool::ClientLevelShutdownPreEntity()
+{
+ DrawCommentaryNodeEntitiesInEngine( false );
+ BaseClass::ClientLevelShutdownPreEntity();
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get a new scheme to be applied to this tool
+//-----------------------------------------------------------------------------
+vgui::HScheme CCommEditTool::GetToolScheme()
+{
+ return vgui::scheme()->LoadSchemeFromFile( "Resource/BoxRocket.res", "BoxRocket" );
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// The View menu
+//
+//-----------------------------------------------------------------------------
+class CCommEditViewMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CCommEditViewMenuButton, CToolMenuButton );
+public:
+ CCommEditViewMenuButton( CCommEditTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+
+private:
+ CCommEditTool *m_pTool;
+};
+
+CCommEditViewMenuButton::CCommEditViewMenuButton( CCommEditTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ m_pTool = parent;
+
+ AddCheckableMenuItem( "properties", "#CommEditProperties", new KeyValues( "OnToggleProperties" ), pActionSignalTarget );
+ AddCheckableMenuItem( "commentarynodebrowser", "#CommEditEntityReport", new KeyValues( "OnToggleEntityReport" ), pActionSignalTarget );
+ AddCheckableMenuItem( "console", "#BxConsole", new KeyValues( "ToggleConsole" ), pActionSignalTarget );
+
+ AddSeparator();
+
+ AddMenuItem( "defaultlayout", "#CommEditViewDefault", new KeyValues( "OnDefaultLayout" ), pActionSignalTarget );
+
+ SetMenu(m_pMenu);
+}
+
+void CCommEditViewMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ int id;
+
+ CCommEditDoc *pDoc = m_pTool->GetDocument();
+ if ( pDoc )
+ {
+ id = m_Items.Find( "properties" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ Panel *p;
+ p = m_pTool->GetProperties();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+
+ id = m_Items.Find( "commentarynodebrowser" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ p = m_pTool->GetCommentaryNodeBrowser();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+
+ id = m_Items.Find( "console" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ CConsolePage *console = m_pTool->GetConsole();
+ m_pMenu->SetMenuItemChecked( id, console->GetParent() );
+ }
+ else
+ {
+ id = m_Items.Find( "properties" );
+ m_pMenu->SetItemEnabled( id, false );
+ id = m_Items.Find( "commentarynodebrowser" );
+ m_pMenu->SetItemEnabled( id, false );
+ id = m_Items.Find( "console" );
+ m_pMenu->SetItemEnabled( id, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// The Tool menu
+//
+//-----------------------------------------------------------------------------
+class CCommEditToolMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CCommEditToolMenuButton, CToolMenuButton );
+public:
+ CCommEditToolMenuButton( CCommEditTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+
+private:
+ CCommEditTool *m_pTool;
+};
+
+CCommEditToolMenuButton::CCommEditToolMenuButton( CCommEditTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ m_pTool = parent;
+
+ AddMenuItem( "addnewnodes", "#CommEditAddNewNodes", new KeyValues( "AddNewNodes" ), pActionSignalTarget, NULL, "CommEditAddNewNodes" );
+
+ SetMenu(m_pMenu);
+}
+
+void CCommEditToolMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ int id;
+
+ CCommEditDoc *pDoc = m_pTool->GetDocument();
+ id = m_Items.Find( "addnewnodes" );
+ m_pMenu->SetItemEnabled( id, pDoc != NULL );
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the menu bar
+//-----------------------------------------------------------------------------
+vgui::MenuBar *CCommEditTool::CreateMenuBar( CBaseToolSystem *pParent )
+{
+ m_pMenuBar = new CToolFileMenuBar( pParent, "Main Menu Bar" );
+
+ // Sets info in the menu bar
+ char title[ 64 ];
+ ComputeMenuBarTitle( title, sizeof( title ) );
+ m_pMenuBar->SetInfo( title );
+ m_pMenuBar->SetToolName( GetToolName() );
+
+ // Add menu buttons
+ CToolMenuButton *pFileButton = CreateToolFileMenuButton( m_pMenuBar, "File", "&File", GetActionTarget(), this );
+ CToolMenuButton *pEditButton = CreateToolEditMenuButton( this, "Edit", "&Edit", GetActionTarget() );
+ CCommEditToolMenuButton *pToolButton = new CCommEditToolMenuButton( this, "CommEdit", "&CommEdit", GetActionTarget() );
+ CCommEditViewMenuButton *pViewButton = new CCommEditViewMenuButton( this, "View", "&View", GetActionTarget() );
+ CToolMenuButton *pSwitchButton = CreateToolSwitchMenuButton( m_pMenuBar, "Switcher", "&Tools", GetActionTarget() );
+
+ m_pMenuBar->AddButton( pFileButton );
+ m_pMenuBar->AddButton( pEditButton );
+ m_pMenuBar->AddButton( pToolButton );
+ m_pMenuBar->AddButton( pViewButton );
+ m_pMenuBar->AddButton( pSwitchButton );
+
+ return m_pMenuBar;
+}
+
+
+//-----------------------------------------------------------------------------
+// Updates the menu bar based on the current file
+//-----------------------------------------------------------------------------
+void CCommEditTool::UpdateMenuBar( )
+{
+ if ( !m_pDoc )
+ {
+ m_pMenuBar->SetFileName( "#CommEditNoFile" );
+ return;
+ }
+
+ const char *pTXTFile = m_pDoc->GetTXTFileName();
+ if ( !pTXTFile[0] )
+ {
+ m_pMenuBar->SetFileName( "#CommEditNoFile" );
+ return;
+ }
+
+ if ( m_pDoc->IsDirty() )
+ {
+ char sz[ 512 ];
+ Q_snprintf( sz, sizeof( sz ), "* %s", pTXTFile );
+ m_pMenuBar->SetFileName( sz );
+ }
+ else
+ {
+ m_pMenuBar->SetFileName( pTXTFile );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets at tool windows
+//-----------------------------------------------------------------------------
+CCommentaryPropertiesPanel *CCommEditTool::GetProperties()
+{
+ return m_hProperties.Get();
+}
+
+CCommentaryNodeBrowserPanel *CCommEditTool::GetCommentaryNodeBrowser()
+{
+ return m_hCommentaryNodeBrowser.Get();
+}
+
+CConsolePage *CCommEditTool::GetConsole()
+{
+ return m_hConsole;
+}
+
+
+//-----------------------------------------------------------------------------
+// Shows element properties
+//-----------------------------------------------------------------------------
+void CCommEditTool::ShowElementProperties( )
+{
+ if ( !m_pDoc )
+ return;
+
+ // It should already exist
+ Assert( m_hProperties.Get() );
+ if ( m_hProperties.Get() )
+ {
+ m_hProperties->SetObject( m_hCurrentEntity );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Destroys all tool windows
+//-----------------------------------------------------------------------------
+void CCommEditTool::ShowEntityInEntityProperties( CDmeCommentaryNodeEntity *pEntity )
+{
+ Assert( m_hProperties.Get() );
+ m_hCurrentEntity = pEntity;
+ m_hProperties->SetObject( m_hCurrentEntity );
+}
+
+
+//-----------------------------------------------------------------------------
+// Destroys all tool windows
+//-----------------------------------------------------------------------------
+void CCommEditTool::DestroyToolContainers()
+{
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets up the default layout
+//-----------------------------------------------------------------------------
+void CCommEditTool::OnDefaultLayout()
+{
+ int y = m_pMenuBar->GetTall();
+
+ int usew, useh;
+ GetSize( usew, useh );
+
+ DestroyToolContainers();
+
+ Assert( ToolWindow::GetToolWindowCount() == 0 );
+
+ CCommentaryPropertiesPanel *properties = GetProperties();
+ CCommentaryNodeBrowserPanel *pEntityReport = GetCommentaryNodeBrowser();
+ CConsolePage *pConsole = GetConsole();
+
+ // Need three containers
+ ToolWindow *pPropertyWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, properties, "#CommEditProperties", false );
+ ToolWindow *pEntityReportWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, pEntityReport, "#CommEditEntityReport", false );
+
+ ToolWindow *pMiniViewport = dynamic_cast< ToolWindow* >( GetMiniViewport() );
+ pMiniViewport->AddPage( pConsole, "#BxConsole", false );
+
+ int halfScreen = usew / 2;
+ int bottom = useh - y;
+ int sy = (bottom - y) / 2;
+ SetMiniViewportBounds( halfScreen, y, halfScreen, sy - y );
+ pEntityReportWindow->SetBounds( 0, y, halfScreen, bottom - y );
+ pPropertyWindow->SetBounds( halfScreen, sy, halfScreen, bottom - sy );
+}
+
+void CCommEditTool::OnToggleProperties()
+{
+ if ( m_hProperties.Get() )
+ {
+ ToggleToolWindow( m_hProperties.Get(), "#CommEditProperties" );
+ }
+}
+
+void CCommEditTool::OnToggleEntityReport()
+{
+ if ( m_hCommentaryNodeBrowser.Get() )
+ {
+ ToggleToolWindow( m_hCommentaryNodeBrowser.Get(), "#CommEditEntityReport" );
+ }
+}
+
+void CCommEditTool::OnToggleConsole()
+{
+ if ( m_hConsole.Get() )
+ {
+ ToggleToolWindow( m_hConsole.Get(), "#BxConsole" );
+ }
+}
+
+void CCommEditTool::BringConsoleToFront()
+{
+ CConsolePage *p = GetConsole();
+ Panel *pPage = p ? p->GetParent() : NULL;
+ if ( pPage == NULL )
+ {
+ OnToggleConsole();
+ }
+ else
+ {
+ ToolWindow *tw = dynamic_cast< ToolWindow * >( pPage->GetParent() );
+ if ( tw )
+ {
+ if ( tw->GetActivePage() != p )
+ {
+ tw->SetActivePage( p );
+ vgui::surface()->SetForegroundWindow( tw->GetVPanel() );
+ p->TextEntryRequestFocus();
+ }
+ else
+ {
+ PropertySheet *pSheet = tw->GetPropertySheet();
+ int nPageCount = pSheet->GetNumPages();
+ int i;
+ for ( i = 0; i < nPageCount; ++i )
+ {
+ if ( p == pSheet->GetPage(i) )
+ break;
+ }
+ i = ( i + 1 ) % nPageCount;
+ pSheet->SetActivePage( pSheet->GetPage(i) );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates
+//-----------------------------------------------------------------------------
+void CCommEditTool::CreateTools( CCommEditDoc *doc )
+{
+ if ( !m_hProperties.Get() )
+ {
+ m_hProperties = new CCommentaryPropertiesPanel( m_pDoc, this );
+ }
+
+ if ( !m_hCommentaryNodeBrowser.Get() )
+ {
+ m_hCommentaryNodeBrowser = new CCommentaryNodeBrowserPanel( m_pDoc, this, "CommentaryNodeBrowserPanel" );
+ }
+
+ if ( !m_hConsole.Get() )
+ {
+ m_hConsole = new CConsolePage( NULL, false );
+ }
+
+ RegisterToolWindow( m_hProperties );
+ RegisterToolWindow( m_hCommentaryNodeBrowser );
+ RegisterToolWindow( m_hConsole );
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the tools
+//-----------------------------------------------------------------------------
+void CCommEditTool::InitTools()
+{
+ ShowElementProperties();
+
+ // FIXME: There are no tool windows here; how should this work?
+ // These panels are saved
+ windowposmgr->RegisterPanel( "properties", m_hProperties, false );
+ windowposmgr->RegisterPanel( "commentarynodebrowser", m_hCommentaryNodeBrowser, false );
+ windowposmgr->RegisterPanel( "Console", m_hConsole, false ); // No context menu
+
+ if ( !windowposmgr->LoadPositions( "cfg/commedit.txt", this, &m_ToolWindowFactory, "CommEdit" ) )
+ {
+ OnDefaultLayout();
+ }
+}
+
+
+void CCommEditTool::DestroyTools()
+{
+ m_hCurrentEntity = NULL;
+
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+
+ UnregisterAllToolWindows();
+
+ if ( m_hProperties.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hProperties.Get() );
+ delete m_hProperties.Get();
+ m_hProperties = NULL;
+ }
+
+ if ( m_hCommentaryNodeBrowser.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hCommentaryNodeBrowser.Get() );
+ delete m_hCommentaryNodeBrowser.Get();
+ m_hCommentaryNodeBrowser = NULL;
+ }
+
+ if ( m_hConsole.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hConsole.Get() );
+ delete m_hConsole.Get();
+ m_hConsole = NULL;
+ }
+}
+
+
+void CCommEditTool::ShowToolWindow( Panel *tool, char const *toolName, bool visible )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL && visible )
+ {
+ m_ToolWindowFactory.InstanceToolWindow( this, false, tool, toolName, false );
+ }
+ else if ( !visible )
+ {
+ ToolWindow *tw = dynamic_cast< ToolWindow * >( tool->GetParent()->GetParent() );
+ Assert( tw );
+ tw->RemovePage( tool );
+ }
+}
+
+void CCommEditTool::ToggleToolWindow( Panel *tool, char const *toolName )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL )
+ {
+ ShowToolWindow( tool, toolName, true );
+ }
+ else
+ {
+ ShowToolWindow( tool, toolName, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates the action menu
+//-----------------------------------------------------------------------------
+vgui::Menu *CCommEditTool::CreateActionMenu( vgui::Panel *pParent )
+{
+ vgui::Menu *pActionMenu = new Menu( pParent, "ActionMenu" );
+ pActionMenu->AddMenuItem( "#ToolHide", new KeyValues( "Command", "command", "HideActionMenu" ), GetActionTarget() );
+ return pActionMenu;
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from IFileMenuCallbacks
+//-----------------------------------------------------------------------------
+int CCommEditTool::GetFileMenuItemsEnabled( )
+{
+ int nFlags = FILE_ALL;
+ if ( m_RecentFiles.IsEmpty() )
+ {
+ nFlags &= ~(FILE_RECENT | FILE_CLEAR_RECENT);
+ }
+ return nFlags;
+}
+
+void CCommEditTool::AddRecentFilesToMenu( vgui::Menu *pMenu )
+{
+ m_RecentFiles.AddToMenu( pMenu, GetActionTarget(), "OnRecent" );
+}
+
+bool CCommEditTool::GetPerforceFileName( char *pFileName, int nMaxLen )
+{
+ if ( !m_pDoc )
+ return false;
+
+ Q_strncpy( pFileName, m_pDoc->GetTXTFileName(), nMaxLen );
+ return pFileName[0] != 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+void CCommEditTool::OnExit()
+{
+ windowposmgr->SavePositions( "cfg/commedit.txt", "CommEdit" );
+
+ enginetools->Command( "quit\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Handle commands from the action menu and other menus
+//-----------------------------------------------------------------------------
+void CCommEditTool::OnCommand( const char *cmd )
+{
+ if ( !V_stricmp( cmd, "HideActionMenu" ) )
+ {
+ if ( GetActionMenu() )
+ {
+ GetActionMenu()->SetVisible( false );
+ }
+ }
+ else if ( const char *pSuffix = StringAfterPrefix( cmd, "OnRecent" ) )
+ {
+ int idx = Q_atoi( pSuffix );
+ OpenFileFromHistory( idx );
+ }
+ else if ( const char *pSuffixTool = StringAfterPrefix( cmd, "OnTool" ) )
+ {
+ int idx = Q_atoi( pSuffixTool );
+ enginetools->SwitchToTool( idx );
+ }
+ else if ( !V_stricmp( cmd, "OnUndo" ) )
+ {
+ OnUndo();
+ }
+ else if ( !V_stricmp( cmd, "OnRedo" ) )
+ {
+ OnRedo();
+ }
+ else if ( !V_stricmp( cmd, "OnDescribeUndo" ) )
+ {
+ OnDescribeUndo();
+ }
+ else
+ {
+ BaseClass::OnCommand( cmd );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Command handlers
+//-----------------------------------------------------------------------------
+void CCommEditTool::OnNew()
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetTXTFileName();
+ }
+
+ // Bring up the file open dialog to choose a .bsp file
+ OpenFile( "bsp", pSaveFileName, "txt", nFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when the File->Open menu is selected
+//-----------------------------------------------------------------------------
+void CCommEditTool::OnOpen( )
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetTXTFileName();
+ }
+
+ OpenFile( "txt", pSaveFileName, "txt", nFlags );
+}
+
+bool CCommEditTool::OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ OnCloseNoSave();
+ if ( !LoadDocument( pFileName ) )
+ return false;
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ UpdateMenuBar();
+ return true;
+}
+
+void CCommEditTool::Save()
+{
+ if ( m_pDoc )
+ {
+ SaveFile( m_pDoc->GetTXTFileName(), "txt", FOSM_SHOW_PERFORCE_DIALOGS );
+ }
+}
+
+void CCommEditTool::OnSaveAs()
+{
+ if ( m_pDoc )
+ {
+ SaveFile( NULL, "txt", FOSM_SHOW_PERFORCE_DIALOGS );
+ }
+}
+
+void CCommEditTool::OnRestartLevel()
+{
+ enginetools->Command( "restart" );
+ enginetools->Execute();
+
+ CDmrCommentaryNodeEntityList entities = m_pDoc->GetEntityList();
+ int nCount = entities.IsValid() ? entities.Count() : 0;
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeCommentaryNodeEntity *pEntity = entities[i];
+ Assert( pEntity );
+ pEntity->MarkDirty( false );
+ }
+}
+
+void CCommEditTool::SaveAndTest()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetTXTFileName(), "txt", FOSM_SHOW_PERFORCE_DIALOGS,
+ new KeyValues( "RestartLevel" ) );
+ }
+ else
+ {
+ OnRestartLevel();
+ }
+}
+
+bool CCommEditTool::OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ if ( !m_pDoc )
+ return false;
+
+ m_pDoc->SetTXTFileName( pFileName );
+ m_pDoc->SaveToFile( );
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ UpdateMenuBar();
+ return true;
+}
+
+void CCommEditTool::OnClose()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetTXTFileName(), "txt", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnClose" ) );
+ return;
+ }
+
+ OnCloseNoSave();
+}
+
+void CCommEditTool::OnCloseNoSave()
+{
+ DestroyTools();
+
+ if ( m_pDoc )
+ {
+ CAppNotifyScopeGuard sg( "CCommEditTool::OnCloseNoSave", 0 );
+
+ delete m_pDoc;
+ m_pDoc = NULL;
+
+ if ( m_hProperties )
+ {
+ m_hProperties->SetObject( NULL );
+ }
+ }
+
+ UpdateMenuBar( );
+}
+
+void CCommEditTool::CenterView( CDmeCommentaryNodeEntity *pEntity )
+{
+ EntitySearchResult pPlayer = clienttools->GetLocalPlayer();
+
+ Vector vecOrigin = pEntity->GetRenderOrigin();
+ QAngle angles = pEntity->GetRenderAngles();
+
+ Vector vecForward, vecUp, vecRight;
+ AngleVectors( angles, &vecForward, &vecRight, &vecUp );
+ VectorMA( vecOrigin, 40.0f, vecForward, vecOrigin );
+ vecForward *= -1.0f;
+ VectorAngles( vecForward, vecUp, angles );
+
+ servertools->SnapPlayerToPosition( vecOrigin, angles, ( IClientEntity* )pPlayer );
+}
+
+
+void CCommEditTool::OnMarkNotDirty()
+{
+ if ( m_pDoc )
+ {
+ m_pDoc->SetDirty( false );
+ }
+}
+
+void CCommEditTool::AttachAllEngineEntities()
+{
+ if ( !clienttools || !m_pDoc )
+ return;
+
+ for ( EntitySearchResult sr = clienttools->FirstEntity(); sr != NULL; sr = clienttools->NextEntity( sr ) )
+ {
+ if ( !sr )
+ continue;
+
+ HTOOLHANDLE handle = clienttools->AttachToEntity( sr );
+
+ const char *pClassName = clienttools->GetClassname( handle );
+ if ( Q_strcmp( pClassName, "class C_PointCommentaryNode" ) == 0 )
+ {
+ Vector vecOrigin = clienttools->GetAbsOrigin( handle );
+ QAngle angAngles = clienttools->GetAbsAngles( handle );
+
+ // Find the associated commentary node entry in our doc
+ CDmeCommentaryNodeEntity *pNode = m_pDoc->GetCommentaryNodeForLocation( vecOrigin, angAngles );
+ if ( pNode )
+ {
+ pNode->AttachToEngineEntity( handle );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Show the save document query dialog
+//-----------------------------------------------------------------------------
+void CCommEditTool::OpenSpecificFile( const char *pFileName )
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc )
+ {
+ // File is already open
+ if ( !Q_stricmp( m_pDoc->GetTXTFileName(), pFileName ) )
+ return;
+
+ if ( m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetTXTFileName();
+ }
+ else
+ {
+ OnCloseNoSave();
+ }
+ }
+
+ OpenFile( pFileName, "txt", pSaveFileName, "txt", nFlags );
+}
+
+void CCommEditTool::OpenFileFromHistory( int slot )
+{
+ const char *pFileName = m_RecentFiles.GetFile( slot );
+ if ( !pFileName )
+ return;
+ OpenSpecificFile( pFileName );
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get notified when files are saved/loaded
+//-----------------------------------------------------------------------------
+void CCommEditTool::OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues )
+{
+ if ( bWroteFile )
+ {
+ OnMarkNotDirty();
+ }
+
+ if ( !pContextKeyValues )
+ return;
+
+ if ( state != FileOpenStateMachine::SUCCESSFUL )
+ return;
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnClose" ) )
+ {
+ OnCloseNoSave();
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnQuit" ) )
+ {
+ OnCloseNoSave();
+ vgui::ivgui()->PostMessage( GetVPanel(), new KeyValues( "OnExit" ), 0 );
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "RestartLevel" ) )
+ {
+ OnRestartLevel();
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the File browser dialog
+//-----------------------------------------------------------------------------
+void CCommEditTool::SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ char pStartingDir[ MAX_PATH ];
+
+ GetModSubdirectory( "maps", pStartingDir, sizeof(pStartingDir) );
+
+ if ( !Q_stricmp( pFileFormat, "bsp" ) )
+ {
+ // Open a bsp file to create a new commentary file
+ pDialog->SetTitle( "Choose BSP File", true );
+ pDialog->SetStartDirectoryContext( "commedit_bsp_session", pStartingDir );
+ pDialog->AddFilter( "*.bsp", "Valve BSP File (*.bsp)", true );
+ }
+ else
+ {
+ // Open existing commentary text files
+ pDialog->SetTitle( "Choose Valve Commentary File", true );
+ pDialog->SetStartDirectoryContext( "commedit_txt_session", pStartingDir );
+ pDialog->AddFilter( "*.txt", "Valve Commentary File (*.txt)", true );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Can we quit?
+//-----------------------------------------------------------------------------
+bool CCommEditTool::CanQuit()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ // Show Save changes Yes/No/Cancel and re-quit if hit yes/no
+ SaveFile( m_pDoc->GetTXTFileName(), "txt", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnQuit" ) );
+ return false;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Various command handlers related to the Edit menu
+//-----------------------------------------------------------------------------
+void CCommEditTool::OnUndo()
+{
+ CDisableUndoScopeGuard guard;
+ g_pDataModel->Undo();
+}
+
+void CCommEditTool::OnRedo()
+{
+ CDisableUndoScopeGuard guard;
+ g_pDataModel->Redo();
+}
+
+void CCommEditTool::OnDescribeUndo()
+{
+ CUtlVector< UndoInfo_t > list;
+ g_pDataModel->GetUndoInfo( list );
+
+ Msg( "%i operations in stack\n", list.Count() );
+
+ for ( int i = list.Count() - 1; i >= 0; --i )
+ {
+ UndoInfo_t& entry = list[ i ];
+ if ( entry.terminator )
+ {
+ Msg( "[ '%s' ] - %i operations\n", entry.undo, entry.numoperations );
+ }
+
+ Msg( " +%s\n", entry.desc );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// CommEdit menu items
+//-----------------------------------------------------------------------------
+void CCommEditTool::OnAddNewNodes()
+{
+ if ( !m_pDoc )
+ return;
+
+ EnterNodeDropMode();
+}
+
+
+//-----------------------------------------------------------------------------
+// Background
+//-----------------------------------------------------------------------------
+const char *CCommEditTool::GetLogoTextureName()
+{
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from ICommEditDocCallback
+//-----------------------------------------------------------------------------
+void CCommEditTool::OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ if ( GetCommentaryNodeBrowser() )
+ {
+ GetCommentaryNodeBrowser()->UpdateEntityList();
+ }
+
+ UpdateMenuBar();
+
+ /*
+ if ( bRefreshUI && m_hProperties.Get() )
+ {
+ m_hProperties->Refresh();
+ }
+ */
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads up a new document
+//-----------------------------------------------------------------------------
+bool CCommEditTool::LoadDocument( const char *pDocName )
+{
+ Assert( !m_pDoc );
+
+ DestroyTools();
+
+ m_pDoc = new CCommEditDoc( this );
+ if ( !m_pDoc->LoadFromFile( pDocName ) )
+ {
+ delete m_pDoc;
+ m_pDoc = NULL;
+ Warning( "Fatal error loading '%s'\n", pDocName );
+ return false;
+ }
+
+ ShowMiniViewport( true );
+
+ CreateTools( m_pDoc );
+ InitTools();
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Create the entities that are in our TXT file
+//-----------------------------------------------------------------------------
+const char* CCommEditTool::GetEntityData( const char *pActualEntityData )
+{
+// if ( !m_pDoc )
+ return pActualEntityData;
+
+// return m_pDoc->GenerateEntityData( pActualEntityData );
+}
diff --git a/tools/commedit/commedittool.h b/tools/commedit/commedittool.h
new file mode 100644
index 0000000..7a5af7e
--- /dev/null
+++ b/tools/commedit/commedittool.h
@@ -0,0 +1,231 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: CommEdit tool; main UI smarts class
+//
+//=============================================================================
+
+#ifndef COMMEDITTOOL_H
+#define COMMEDITTOOL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/platform.h"
+#include "toolutils/basetoolsystem.h"
+#include "toolutils/recentfilelist.h"
+#include "toolutils/toolmenubar.h"
+#include "toolutils/toolswitchmenubutton.h"
+#include "toolutils/tooleditmenubutton.h"
+#include "toolutils/toolfilemenubutton.h"
+#include "toolutils/toolmenubutton.h"
+#include "datamodel/dmelement.h"
+#include "dmecommentarynodeentity.h"
+#include "toolframework/ienginetool.h"
+#include "toolutils/enginetools_int.h"
+#include "toolutils/savewindowpositions.h"
+#include "toolutils/toolwindowfactory.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CDmElement;
+class CConsolePage;
+class CCommEditDoc;
+class CCommentaryPropertiesPanel;
+class CCommentaryNodeBrowserPanel;
+
+namespace vgui
+{
+ class Panel;
+}
+
+
+//-----------------------------------------------------------------------------
+// Allows the doc to call back into the CommEdit editor tool
+//-----------------------------------------------------------------------------
+abstract_class ICommEditDocCallback
+{
+public:
+ // Called by the doc when the data changes
+ virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags ) = 0;
+};
+
+
+//-----------------------------------------------------------------------------
+// Global methods of the commedit tool
+//-----------------------------------------------------------------------------
+abstract_class ICommEditTool
+{
+public:
+ // Gets at the rool panel (for modal dialogs)
+ virtual vgui::Panel *GetRootPanel() = 0;
+
+ // Gets the registry name (for saving settings)
+ virtual const char *GetRegistryName() = 0;
+
+ // Shows a particular entity in the entity properties dialog
+ virtual void ShowEntityInEntityProperties( CDmeCommentaryNodeEntity *pEntity ) = 0;
+};
+
+//-----------------------------------------------------------------------------
+// Implementation of the CommEdit tool
+//-----------------------------------------------------------------------------
+class CCommEditTool : public CBaseToolSystem, public IFileMenuCallbacks, public ICommEditDocCallback, public ICommEditTool
+{
+ DECLARE_CLASS_SIMPLE( CCommEditTool, CBaseToolSystem );
+
+public:
+ CCommEditTool();
+
+ // Inherited from IToolSystem
+ virtual const char *GetToolName() { return "Commentary Editor"; }
+ virtual bool Init( );
+ virtual void Shutdown();
+ virtual bool CanQuit();
+ virtual void OnToolActivate();
+ virtual void OnToolDeactivate();
+ virtual const char* GetEntityData( const char *pActualEntityData );
+ virtual void DrawCommentaryNodeEntitiesInEngine( bool bDrawInEngine );
+ virtual void ClientLevelInitPostEntity();
+ virtual void ClientLevelShutdownPreEntity();
+ virtual bool TrapKey( ButtonCode_t key, bool down );
+ virtual void ClientPreRender();
+
+ // Inherited from IFileMenuCallbacks
+ virtual int GetFileMenuItemsEnabled( );
+ virtual void AddRecentFilesToMenu( vgui::Menu *menu );
+ virtual bool GetPerforceFileName( char *pFileName, int nMaxLen );
+
+ // Inherited from ICommEditDocCallback
+ virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+ virtual vgui::Panel *GetRootPanel() { return this; }
+ virtual void ShowEntityInEntityProperties( CDmeCommentaryNodeEntity *pEntity );
+
+ // Inherited from CBaseToolSystem
+ virtual vgui::HScheme GetToolScheme();
+ virtual vgui::Menu *CreateActionMenu( vgui::Panel *pParent );
+ virtual void OnCommand( const char *cmd );
+ virtual const char *GetRegistryName() { return "CommEditTool"; }
+ virtual const char *GetBindingsContextFile() { return "cfg/CommEdit.kb"; }
+ virtual vgui::MenuBar *CreateMenuBar( CBaseToolSystem *pParent );
+
+ MESSAGE_FUNC( Save, "OnSave" );
+ void SaveAndTest();
+ void CenterView( CDmeCommentaryNodeEntity* pEntity );
+
+ // Enter mode where we preview dropping nodes
+ void EnterNodeDropMode();
+ void LeaveNodeDropMode();
+
+public:
+ MESSAGE_FUNC( OnRestartLevel, "RestartLevel" );
+ MESSAGE_FUNC( OnNew, "OnNew" );
+ MESSAGE_FUNC( OnOpen, "OnOpen" );
+ MESSAGE_FUNC( OnSaveAs, "OnSaveAs" );
+ MESSAGE_FUNC( OnClose, "OnClose" );
+ MESSAGE_FUNC( OnCloseNoSave, "OnCloseNoSave" );
+ MESSAGE_FUNC( OnMarkNotDirty, "OnMarkNotDirty" );
+ MESSAGE_FUNC( OnExit, "OnExit" );
+
+ // Commands related to the edit menu
+ void OnDescribeUndo();
+
+ // Methods related to the CommEdit menu
+ MESSAGE_FUNC( OnAddNewNodes, "AddNewNodes" );
+
+ // Methods related to the view menu
+ MESSAGE_FUNC( OnToggleProperties, "OnToggleProperties" );
+ MESSAGE_FUNC( OnToggleEntityReport, "OnToggleEntityReport" );
+ MESSAGE_FUNC( OnToggleConsole, "ToggleConsole" );
+
+ MESSAGE_FUNC( OnDefaultLayout, "OnDefaultLayout" );
+
+ // Keybindings
+ KEYBINDING_FUNC( undo, KEY_Z, vgui::MODIFIER_CONTROL, OnUndo, "#undo_help", 0 );
+ KEYBINDING_FUNC( redo, KEY_Z, vgui::MODIFIER_CONTROL | vgui::MODIFIER_SHIFT, OnRedo, "#redo_help", 0 );
+ KEYBINDING_FUNC_NODECLARE( CommEditAddNewNodes, KEY_A, vgui::MODIFIER_CONTROL, OnAddNewNodes, "#CommEditAddNewNodesHelp", 0 );
+
+ void PerformNew();
+ void OpenFileFromHistory( int slot );
+ void OpenSpecificFile( const char *pFileName );
+ virtual void SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual void OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues );
+
+ void AttachAllEngineEntities();
+
+ // returns the document
+ CCommEditDoc *GetDocument();
+
+ // Gets at tool windows
+ CCommentaryPropertiesPanel *GetProperties();
+ CCommentaryNodeBrowserPanel *GetCommentaryNodeBrowser();
+ CConsolePage *GetConsole();
+
+ CDmeHandle< CDmeCommentaryNodeEntity > GetCurrentEntity( void ) { return m_hCurrentEntity; }
+
+private:
+ // Loads up a new document
+ bool LoadDocument( const char *pDocName );
+
+ // Updates the menu bar based on the current file
+ void UpdateMenuBar( );
+
+ // Shows element properties
+ void ShowElementProperties( );
+
+ virtual const char *GetLogoTextureName();
+
+ // Creates, destroys tools
+ void CreateTools( CCommEditDoc *doc );
+ void DestroyTools();
+
+ // Initializes the tools
+ void InitTools();
+
+ // Shows, toggles tool windows
+ void ToggleToolWindow( Panel *tool, char const *toolName );
+ void ShowToolWindow( Panel *tool, char const *toolName, bool visible );
+
+ // Kills all tool windows
+ void DestroyToolContainers();
+
+ // Gets the position of the preview object
+ void GetPlacementInfo( Vector &vecOrigin, QAngle &angles );
+
+ // Brings the console to front
+ void BringConsoleToFront();
+
+private:
+ // Document
+ CCommEditDoc *m_pDoc;
+
+ // The menu bar
+ CToolFileMenuBar *m_pMenuBar;
+
+ // Element properties for editing material
+ vgui::DHANDLE< CCommentaryPropertiesPanel > m_hProperties;
+
+ // The entity report
+ vgui::DHANDLE< CCommentaryNodeBrowserPanel > m_hCommentaryNodeBrowser;
+
+ // The console
+ vgui::DHANDLE< CConsolePage > m_hConsole;
+
+ // The currently viewed entity
+ CDmeHandle< CDmeCommentaryNodeEntity > m_hCurrentEntity;
+
+ // Separate undo context for the act busy tool
+ bool m_bInNodeDropMode;
+ bool m_bDroppingCommentaryNodes;
+ CDmeHandle< CDmeCommentaryNodeEntity > m_hPreviewNode;
+ CDmeHandle< CDmeCommentaryNodeEntity > m_hPreviewTarget;
+ CToolWindowFactory< ToolWindow > m_ToolWindowFactory;
+};
+
+extern CCommEditTool *g_pCommEditTool;
+
+#endif // COMMEDITTOOL_H
diff --git a/tools/commedit/commentarynodebrowserpanel.cpp b/tools/commedit/commentarynodebrowserpanel.cpp
new file mode 100644
index 0000000..aa76156
--- /dev/null
+++ b/tools/commedit/commentarynodebrowserpanel.cpp
@@ -0,0 +1,283 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Singleton dialog that generates and presents the entity report.
+//
+//===========================================================================//
+
+#include "CommentaryNodeBrowserPanel.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "iregistry.h"
+#include "vgui/ivgui.h"
+#include "vgui_controls/listpanel.h"
+#include "vgui_controls/textentry.h"
+#include "vgui_controls/checkbutton.h"
+#include "vgui_controls/combobox.h"
+#include "vgui_controls/radiobutton.h"
+#include "vgui_controls/messagebox.h"
+#include "commeditdoc.h"
+#include "commedittool.h"
+#include "datamodel/dmelement.h"
+#include "vgui/keycode.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Sort by target name
+//-----------------------------------------------------------------------------
+static int __cdecl TargetNameSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ const char *string1 = item1.kv->GetString("targetname");
+ const char *string2 = item2.kv->GetString("targetname");
+ int nRetVal = Q_stricmp( string1, string2 );
+ if ( nRetVal != 0 )
+ return nRetVal;
+
+ string1 = item1.kv->GetString("classname");
+ string2 = item2.kv->GetString("classname");
+ return Q_stricmp( string1, string2 );
+}
+
+//-----------------------------------------------------------------------------
+// Sort by class name
+//-----------------------------------------------------------------------------
+static int __cdecl ClassNameSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ const char *string1 = item1.kv->GetString("classname");
+ const char *string2 = item2.kv->GetString("classname");
+ int nRetVal = Q_stricmp( string1, string2 );
+ if ( nRetVal != 0 )
+ return nRetVal;
+
+ string1 = item1.kv->GetString("targetname");
+ string2 = item2.kv->GetString("targetname");
+ return Q_stricmp( string1, string2 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CCommentaryNodeBrowserPanel::CCommentaryNodeBrowserPanel( CCommEditDoc *pDoc, vgui::Panel* pParent, const char *pName )
+ : BaseClass( pParent, pName ), m_pDoc( pDoc )
+{
+ SetPaintBackgroundEnabled( true );
+
+ m_pEntities = new vgui::ListPanel( this, "Entities" );
+ m_pEntities->AddColumnHeader( 0, "targetname", "Name", 52, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pEntities->AddColumnHeader( 1, "classname", "Class Name", 52, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pEntities->SetColumnSortable( 0, true );
+ m_pEntities->SetColumnSortable( 1, true );
+ m_pEntities->SetEmptyListText( "No Entities" );
+ // m_pEntities->SetDragEnabled( true );
+ m_pEntities->AddActionSignalTarget( this );
+ m_pEntities->SetSortFunc( 0, TargetNameSortFunc );
+ m_pEntities->SetSortFunc( 1, ClassNameSortFunc );
+ m_pEntities->SetSortColumn( 0 );
+
+ LoadControlSettingsAndUserConfig( "resource/commentarynodebrowserpanel.res" );
+
+ UpdateEntityList();
+}
+
+CCommentaryNodeBrowserPanel::~CCommentaryNodeBrowserPanel()
+{
+ SaveUserConfig();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Shows the most recent selected object in properties window
+//-----------------------------------------------------------------------------
+void CCommentaryNodeBrowserPanel::OnProperties( )
+{
+ if ( m_pEntities->GetSelectedItemsCount() == 0 )
+ {
+ g_pCommEditTool->ShowEntityInEntityProperties( NULL );
+ return;
+ }
+
+ int iSel = m_pEntities->GetSelectedItem( 0 );
+ KeyValues *kv = m_pEntities->GetItem( iSel );
+ CDmeCommentaryNodeEntity *pEntity = CastElement< CDmeCommentaryNodeEntity >( (CDmElement *)kv->GetPtr( "entity" ) );
+ g_pCommEditTool->ShowEntityInEntityProperties( pEntity );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Deletes the marked objects.
+//-----------------------------------------------------------------------------
+void CCommentaryNodeBrowserPanel::OnDeleteEntities(void)
+{
+ int iSel = m_pEntities->GetSelectedItem( 0 );
+
+ {
+ // This is undoable
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Delete Entities", "Delete Entities" );
+
+ //
+ // Build a list of objects to delete.
+ //
+ int nCount = m_pEntities->GetSelectedItemsCount();
+ for (int i = 0; i < nCount; i++)
+ {
+ int nItemID = m_pEntities->GetSelectedItem(i);
+ KeyValues *kv = m_pEntities->GetItem( nItemID );
+ CDmElement *pEntity = (CDmElement *)kv->GetPtr( "entity" );
+ if ( pEntity )
+ {
+ m_pDoc->DeleteCommentaryNode( pEntity );
+ }
+ }
+ }
+
+ // Update the list box selection.
+ if (iSel >= m_pEntities->GetItemCount())
+ {
+ iSel = m_pEntities->GetItemCount() - 1;
+ }
+ m_pEntities->SetSingleSelectedItem( iSel );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommentaryNodeBrowserPanel::OnKeyCodeTyped( vgui::KeyCode code )
+{
+ if ( code == KEY_DELETE )
+ {
+ OnDeleteEntities();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped( code );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommentaryNodeBrowserPanel::OnItemSelected( void )
+{
+ OnProperties();
+}
+
+
+//-----------------------------------------------------------------------------
+// Select a particular node
+//-----------------------------------------------------------------------------
+void CCommentaryNodeBrowserPanel::SelectNode( CDmeCommentaryNodeEntity *pNode )
+{
+ m_pEntities->ClearSelectedItems();
+ for ( int nItemID = m_pEntities->FirstItem(); nItemID != m_pEntities->InvalidItemID(); nItemID = m_pEntities->NextItem( nItemID ) )
+ {
+ KeyValues *kv = m_pEntities->GetItem( nItemID );
+ CDmElement *pEntity = (CDmElement *)kv->GetPtr( "entity" );
+ if ( pEntity == pNode )
+ {
+ m_pEntities->AddSelectedItem( nItemID );
+ break;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when buttons are clicked
+//-----------------------------------------------------------------------------
+void CCommentaryNodeBrowserPanel::OnCommand( const char *pCommand )
+{
+ if ( !Q_stricmp( pCommand, "delete" ) )
+ {
+ // Confirm we want to do it
+ MessageBox *pConfirm = new MessageBox( "#CommEditDeleteObjects", "#CommEditDeleteObjectsMsg", g_pCommEditTool->GetRootPanel() );
+ pConfirm->AddActionSignalTarget( this );
+ pConfirm->SetOKButtonText( "Yes" );
+ pConfirm->SetCommand( new KeyValues( "DeleteEntities" ) );
+ pConfirm->SetCancelButtonVisible( true );
+ pConfirm->SetCancelButtonText( "No" );
+ pConfirm->DoModal();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "Save" ) )
+ {
+ g_pCommEditTool->Save();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "CenterView" ) )
+ {
+ if ( m_pEntities->GetSelectedItemsCount() == 1 )
+ {
+ int iSel = m_pEntities->GetSelectedItem( 0 );
+ KeyValues *kv = m_pEntities->GetItem( iSel );
+ CDmeCommentaryNodeEntity *pEntity = CastElement< CDmeCommentaryNodeEntity >( (CDmElement *)kv->GetPtr( "entity" ) );
+ g_pCommEditTool->CenterView( pEntity );
+ }
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "SaveAndTest" ) )
+ {
+ g_pCommEditTool->SaveAndTest();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "DropNodes" ) )
+ {
+ g_pCommEditTool->EnterNodeDropMode();
+ return;
+ }
+
+ BaseClass::OnCommand( pCommand );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommentaryNodeBrowserPanel::UpdateEntityList(void)
+{
+ m_pEntities->RemoveAll();
+
+ CDmrCommentaryNodeEntityList entityList( m_pDoc->GetEntityList() );
+ if ( !entityList.IsValid() )
+ return;
+
+ int nCount = entityList.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmElement *pEntity = entityList[i];
+ Assert( pEntity );
+ if ( !pEntity )
+ continue;
+
+ const char *pClassName = pEntity->GetValueString( "classname" );
+ if ( !pClassName || !pClassName[0] )
+ {
+ pClassName = "<no class>";
+ }
+
+ KeyValues *kv = new KeyValues( "node" );
+ kv->SetString( "classname", pClassName );
+ kv->SetPtr( "entity", pEntity );
+
+ const char *pTargetname = pEntity->GetValueString( "targetname" );
+ if ( !pTargetname || !pTargetname[0] )
+ {
+ pTargetname = "<no targetname>";
+ }
+ kv->SetString( "targetname", pTargetname );
+
+ m_pEntities->AddItem( kv, 0, false, false );
+ }
+ m_pEntities->SortList();
+}
+
diff --git a/tools/commedit/commentarynodebrowserpanel.h b/tools/commedit/commentarynodebrowserpanel.h
new file mode 100644
index 0000000..38a7de1
--- /dev/null
+++ b/tools/commedit/commentarynodebrowserpanel.h
@@ -0,0 +1,67 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#ifndef COMMENTARYNODEBROWSERPANEL_H
+#define COMMENTARYNODEBROWSERPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/editablepanel.h"
+#include "tier1/utlstring.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CCommEditDoc;
+class CDmeCommentaryNodeEntity;
+namespace vgui
+{
+ class ComboBox;
+ class Button;
+ class TextEntry;
+ class ListPanel;
+ class CheckButton;
+ class RadioButton;
+}
+
+
+//-----------------------------------------------------------------------------
+// Panel that shows all entities in the level
+//-----------------------------------------------------------------------------
+class CCommentaryNodeBrowserPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CCommentaryNodeBrowserPanel, vgui::EditablePanel );
+
+public:
+ CCommentaryNodeBrowserPanel( CCommEditDoc *pDoc, vgui::Panel* pParent, const char *pName ); // standard constructor
+ virtual ~CCommentaryNodeBrowserPanel();
+
+// Inherited from Panel
+ virtual void OnCommand( const char *pCommand );
+ virtual void OnKeyCodeTyped( vgui::KeyCode code );
+
+ // Methods related to updating the listpanel
+ void UpdateEntityList();
+
+ // Select a particular node
+ void SelectNode( CDmeCommentaryNodeEntity *pNode );
+
+private:
+ // Messages handled
+ MESSAGE_FUNC( OnDeleteEntities, "DeleteEntities" );
+ MESSAGE_FUNC( OnItemSelected, "ItemSelected" );
+
+ // Shows the most recent selected object in properties window
+ void OnProperties();
+
+ CCommEditDoc *m_pDoc;
+ vgui::ListPanel *m_pEntities;
+};
+
+
+#endif // COMMENTARYNODEBROWSERPANEL_H
diff --git a/tools/commedit/commentarypropertiespanel.cpp b/tools/commedit/commentarypropertiespanel.cpp
new file mode 100644
index 0000000..e875bb0
--- /dev/null
+++ b/tools/commedit/commentarypropertiespanel.cpp
@@ -0,0 +1,458 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Singleton dialog that generates and presents the entity report.
+//
+//===========================================================================//
+
+#include "CommentaryPropertiesPanel.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "iregistry.h"
+#include "vgui/ivgui.h"
+#include "vgui_controls/listpanel.h"
+#include "vgui_controls/textentry.h"
+#include "vgui_controls/checkbutton.h"
+#include "vgui_controls/combobox.h"
+#include "vgui_controls/radiobutton.h"
+#include "vgui_controls/messagebox.h"
+#include "vgui_controls/scrollbar.h"
+#include "vgui_controls/scrollableeditablepanel.h"
+#include "commeditdoc.h"
+#include "commedittool.h"
+#include "datamodel/dmelement.h"
+#include "dmecommentarynodeentity.h"
+#include "dme_controls/soundpicker.h"
+#include "dme_controls/soundrecordpanel.h"
+#include "matsys_controls/picker.h"
+#include "vgui_controls/fileopendialog.h"
+#include "filesystem.h"
+#include "tier2/fileutils.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CCommentaryPropertiesPanel::CCommentaryPropertiesPanel( CCommEditDoc *pDoc, vgui::Panel* pParent )
+ : BaseClass( pParent, "CommentaryPropertiesPanel" ), m_pDoc( pDoc )
+{
+ SetPaintBackgroundEnabled( true );
+ SetKeyBoardInputEnabled( true );
+
+ m_pCommentaryNode = new vgui::EditablePanel( (vgui::Panel*)NULL, "CommentaryNode" );
+
+ m_pNodeName = new vgui::TextEntry( m_pCommentaryNode, "CommentaryNodeName" );
+ m_pNodeName->AddActionSignalTarget( this );
+
+ m_pSoundFilePicker = new vgui::Button( m_pCommentaryNode, "AudioFilePickerButton", "", this, "PickSound" );
+
+ m_pSoundFileName = new vgui::TextEntry( m_pCommentaryNode, "AudioFileName" );
+ m_pSoundFileName->AddActionSignalTarget( this );
+
+ m_pRecordSound = new vgui::Button( m_pCommentaryNode, "RecordAudioButton", "", this, "Record" );
+
+ m_pSpeakerName = new vgui::TextEntry( m_pCommentaryNode, "Speaker" );
+ m_pSpeakerName->AddActionSignalTarget( this );
+
+ m_pSynopsis = new vgui::TextEntry( m_pCommentaryNode, "Synopsis" );
+ m_pSynopsis->AddActionSignalTarget( this );
+
+ m_pViewPositionPicker = new vgui::Button( m_pCommentaryNode, "ViewPositionPickerButton", "", this, "PickViewPosition" );
+ m_pViewTargetPicker = new vgui::Button( m_pCommentaryNode, "ViewTargetPickerButton", "", this, "PickViewTarget" );
+
+ m_pViewPosition = new vgui::TextEntry( m_pCommentaryNode, "ViewPosition" );
+ m_pViewPosition->AddActionSignalTarget( this );
+
+ m_pViewTarget = new vgui::TextEntry( m_pCommentaryNode, "ViewTarget" );
+ m_pViewTarget->AddActionSignalTarget( this );
+
+ m_pPreventMovement = new vgui::CheckButton( m_pCommentaryNode, "PreventMovement", "" );
+ m_pPreventMovement->SetCommand( "PreventMovementClicked" );
+ m_pPreventMovement->AddActionSignalTarget( this );
+
+ m_pStartCommands = new vgui::TextEntry( m_pCommentaryNode, "StartCommands" );
+ m_pStartCommands->AddActionSignalTarget( this );
+
+ m_pEndCommands = new vgui::TextEntry( m_pCommentaryNode, "EndCommands" );
+ m_pEndCommands->AddActionSignalTarget( this );
+
+ m_pPosition[0] = new vgui::TextEntry( m_pCommentaryNode, "PositionX" );
+ m_pPosition[0]->AddActionSignalTarget( this );
+ m_pPosition[1] = new vgui::TextEntry( m_pCommentaryNode, "PositionY" );
+ m_pPosition[1]->AddActionSignalTarget( this );
+ m_pPosition[2] = new vgui::TextEntry( m_pCommentaryNode, "PositionZ" );
+ m_pPosition[2]->AddActionSignalTarget( this );
+
+ m_pOrientation[0] = new vgui::TextEntry( m_pCommentaryNode, "Pitch" );
+ m_pOrientation[0]->AddActionSignalTarget( this );
+ m_pOrientation[1] = new vgui::TextEntry( m_pCommentaryNode, "Yaw" );
+ m_pOrientation[1]->AddActionSignalTarget( this );
+ m_pOrientation[2] = new vgui::TextEntry( m_pCommentaryNode, "Roll" );
+ m_pOrientation[2]->AddActionSignalTarget( this );
+
+ m_pCommentaryNode->LoadControlSettings( "resource/commentarypropertiessubpanel_node.res" );
+
+ m_pInfoTarget = new vgui::EditablePanel( (vgui::Panel*)NULL, "InfoTarget" );
+
+ m_pTargetName = new vgui::TextEntry( m_pInfoTarget, "TargetName" );
+ m_pTargetName->AddActionSignalTarget( this );
+
+ m_pTargetPosition[0] = new vgui::TextEntry( m_pInfoTarget, "PositionX" );
+ m_pTargetPosition[0]->AddActionSignalTarget( this );
+ m_pTargetPosition[1] = new vgui::TextEntry( m_pInfoTarget, "PositionY" );
+ m_pTargetPosition[1]->AddActionSignalTarget( this );
+ m_pTargetPosition[2] = new vgui::TextEntry( m_pInfoTarget, "PositionZ" );
+ m_pTargetPosition[2]->AddActionSignalTarget( this );
+
+ m_pTargetOrientation[0] = new vgui::TextEntry( m_pInfoTarget, "Pitch" );
+ m_pTargetOrientation[0]->AddActionSignalTarget( this );
+ m_pTargetOrientation[1] = new vgui::TextEntry( m_pInfoTarget, "Yaw" );
+ m_pTargetOrientation[1]->AddActionSignalTarget( this );
+ m_pTargetOrientation[2] = new vgui::TextEntry( m_pInfoTarget, "Roll" );
+ m_pTargetOrientation[2]->AddActionSignalTarget( this );
+
+ m_pInfoTarget->LoadControlSettings( "resource/commentarypropertiessubpanel_target.res" );
+
+ m_pCommentaryNodeScroll = new vgui::ScrollableEditablePanel( this, m_pCommentaryNode, "CommentaryNodeScroll" );
+ m_pInfoTargetScroll = new vgui::ScrollableEditablePanel( this, m_pInfoTarget, "InfoTargetScroll" );
+
+ LoadControlSettings( "resource/commentarypropertiespanel.res" );
+
+ m_pCommentaryNodeScroll->SetVisible( false );
+ m_pInfoTargetScroll->SetVisible( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Text to attribute...
+//-----------------------------------------------------------------------------
+void CCommentaryPropertiesPanel::TextEntryToAttribute( vgui::TextEntry *pEntry, const char *pAttributeName )
+{
+ int nLen = pEntry->GetTextLength();
+ char *pBuf = (char*)_alloca( nLen+1 );
+ pEntry->GetText( pBuf, nLen+1 );
+ m_hEntity->SetValue( pAttributeName, pBuf );
+}
+
+void CCommentaryPropertiesPanel::TextEntriesToVector( vgui::TextEntry *pEntry[3], const char *pAttributeName )
+{
+ Vector vec;
+ for ( int i = 0; i < 3; ++i )
+ {
+ int nLen = pEntry[i]->GetTextLength();
+ char *pBuf = (char*)_alloca( nLen+1 );
+ pEntry[i]->GetText( pBuf, nLen+1 );
+ vec[i] = atof( pBuf );
+ }
+ m_hEntity->SetValue( pAttributeName, vec );
+ clienttools->MarkClientRenderableDirty( m_hEntity );
+}
+
+
+//-----------------------------------------------------------------------------
+// Updates entity state when text fields change
+//-----------------------------------------------------------------------------
+void CCommentaryPropertiesPanel::UpdateCommentaryNode()
+{
+ if ( !m_hEntity.Get() )
+ return;
+
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Commentary Node Change", "Commentary Node Change" );
+ TextEntryToAttribute( m_pNodeName, "targetname" );
+ TextEntryToAttribute( m_pStartCommands, "precommands" );
+ TextEntryToAttribute( m_pEndCommands, "postcommands" );
+ TextEntryToAttribute( m_pViewPosition, "viewposition" );
+ TextEntryToAttribute( m_pViewTarget, "viewtarget" );
+ TextEntryToAttribute( m_pSynopsis, "synopsis" );
+ TextEntryToAttribute( m_pSpeakerName, "speakers" );
+ TextEntryToAttribute( m_pSoundFileName, "commentaryfile" );
+ TextEntriesToVector( m_pPosition, "origin" );
+ TextEntriesToVector( m_pOrientation, "angles" );
+ m_hEntity->SetValue<int>( "prevent_movement", m_pPreventMovement->IsSelected() ? 1 : 0 );
+ m_hEntity->MarkDirty();
+}
+
+void CCommentaryPropertiesPanel::UpdateInfoTarget()
+{
+ if ( !m_hEntity.Get() )
+ return;
+
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Info Target Change", "Info Target Change" );
+ TextEntryToAttribute( m_pTargetName, "targetname" );
+ TextEntriesToVector( m_pTargetPosition, "origin" );
+ TextEntriesToVector( m_pTargetOrientation, "angles" );
+ m_hEntity->MarkDirty();
+}
+
+
+//-----------------------------------------------------------------------------
+// Populates the commentary node fields
+//-----------------------------------------------------------------------------
+void CCommentaryPropertiesPanel::PopulateCommentaryNodeFields()
+{
+ if ( !m_hEntity.Get() )
+ return;
+
+ m_pNodeName->SetText( m_hEntity->GetTargetName() );
+ m_pStartCommands->SetText( m_hEntity->GetValueString( "precommands" ) );
+ m_pEndCommands->SetText( m_hEntity->GetValueString( "postcommands" ) );
+ m_pViewPosition->SetText( m_hEntity->GetValueString( "viewposition" ) );
+ m_pViewTarget->SetText( m_hEntity->GetValueString( "viewtarget" ) );
+ m_pSynopsis->SetText( m_hEntity->GetValueString( "synopsis" ) );
+ m_pSpeakerName->SetText( m_hEntity->GetValueString( "speakers" ) );
+ m_pSoundFileName->SetText( m_hEntity->GetValueString( "commentaryfile" ) );
+
+ Vector vecPosition = m_hEntity->GetRenderOrigin();
+ QAngle vecAngles = m_hEntity->GetRenderAngles();
+
+ for ( int i = 0; i < 3; ++i )
+ {
+ char pTemp[512];
+ Q_snprintf( pTemp, sizeof(pTemp), "%.2f", vecPosition[i] );
+ m_pPosition[i]->SetText( pTemp );
+
+ Q_snprintf( pTemp, sizeof(pTemp), "%.2f", vecAngles[i] );
+ m_pOrientation[i]->SetText( pTemp );
+ }
+
+ m_pPreventMovement->SetSelected( m_hEntity->GetValue<int>( "prevent_movement" ) != 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Populates the info_target fields
+//-----------------------------------------------------------------------------
+void CCommentaryPropertiesPanel::PopulateInfoTargetFields()
+{
+ if ( !m_hEntity.Get() )
+ return;
+
+ m_pTargetName->SetText( m_hEntity->GetTargetName() );
+
+ Vector vecPosition = m_hEntity->GetRenderOrigin();
+ QAngle vecAngles = m_hEntity->GetRenderAngles();
+
+ for ( int i = 0; i < 3; ++i )
+ {
+ char pTemp[512];
+ Q_snprintf( pTemp, sizeof(pTemp), "%.2f", vecPosition[i] );
+ m_pTargetPosition[i]->SetText( pTemp );
+
+ Q_snprintf( pTemp, sizeof(pTemp), "%.2f", vecAngles[i] );
+ m_pTargetOrientation[i]->SetText( pTemp );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the object to look at
+//-----------------------------------------------------------------------------
+void CCommentaryPropertiesPanel::SetObject( CDmeCommentaryNodeEntity *pEntity )
+{
+ m_hEntity = pEntity;
+ m_pCommentaryNodeScroll->SetVisible( false );
+ m_pInfoTargetScroll->SetVisible( false );
+
+ if ( pEntity )
+ {
+ if ( !Q_stricmp( pEntity->GetClassName(), "info_target" ) )
+ {
+ PopulateInfoTargetFields();
+ m_pInfoTargetScroll->SetVisible( true );
+ m_pTargetName->RequestFocus();
+ return;
+ }
+
+ if ( !Q_stricmp( pEntity->GetClassName(), "point_commentary_node" ) )
+ {
+ PopulateCommentaryNodeFields();
+ m_pCommentaryNodeScroll->SetVisible( true );
+ m_pNodeName->RequestFocus();
+ return;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when text is changed
+//-----------------------------------------------------------------------------
+void CCommentaryPropertiesPanel::OnTextChanged( KeyValues *pParams )
+{
+ vgui::Panel *pPanel = (vgui::Panel*)pParams->GetPtr( "panel" );
+ if ( pPanel->GetParent() == m_pCommentaryNode )
+ {
+ UpdateCommentaryNode();
+ return;
+ }
+
+ if ( pPanel->GetParent() == m_pInfoTarget )
+ {
+ UpdateInfoTarget();
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when the audio picker has picked something
+//-----------------------------------------------------------------------------
+void CCommentaryPropertiesPanel::OnSoundSelected( KeyValues *pParams )
+{
+ const char *pAssetName = pParams->GetString( "wav" );
+ m_pSoundFileName->SetText( pAssetName );
+ UpdateCommentaryNode();
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when the audio picker button is selected
+//-----------------------------------------------------------------------------
+void CCommentaryPropertiesPanel::PickSound()
+{
+ CSoundPickerFrame *pSoundPickerDialog = new CSoundPickerFrame( g_pCommEditTool->GetRootPanel(), "Select commentary audio file", CSoundPicker::PICK_WAVFILES );
+ pSoundPickerDialog->AddActionSignalTarget( this );
+ pSoundPickerDialog->DoModal( CSoundPicker::PICK_NONE, NULL );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when the string picker has picked something
+//-----------------------------------------------------------------------------
+void CCommentaryPropertiesPanel::OnPicked( KeyValues *pParams )
+{
+ const char *pInfoTargetName = pParams->GetString( "choice" );
+ KeyValues *pContextKeyValues = pParams->FindKey( "context" );
+ vgui::TextEntry *pTextEntry = (vgui::TextEntry *)pContextKeyValues->GetPtr( "widget" );
+ pTextEntry->SetText( pInfoTargetName );
+ UpdateCommentaryNode();
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when the audio picker button is selected
+//-----------------------------------------------------------------------------
+void CCommentaryPropertiesPanel::PickInfoTarget( vgui::TextEntry *pControl )
+{
+ CDmrCommentaryNodeEntityList entities( m_pDoc->GetEntityList() );
+ int nCount = entities.Count();
+ PickerList_t vec( 0, nCount+1 );
+ int j = vec.AddToTail( );
+ vec[j].m_pChoiceString = "<no target>";
+ vec[j].m_pChoiceValue = "";
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeCommentaryNodeEntity *pNode = entities[ i ];
+ const char *pTargetName = pNode->GetTargetName();
+ if ( !pTargetName || !pTargetName[0] )
+ continue;
+
+ if ( !Q_stricmp( pNode->GetClassName(), "info_target" ) )
+ {
+ j = vec.AddToTail( );
+ vec[j].m_pChoiceString = pTargetName;
+ vec[j].m_pChoiceValue = pTargetName;
+ }
+ }
+
+ CPickerFrame *pInfoTargetPickerDialog = new CPickerFrame( g_pCommEditTool->GetRootPanel(), "Select Target", "InfoTarget", NULL );
+ KeyValues *pContextKeyValues = new KeyValues( "context" );
+ pContextKeyValues->SetPtr( "widget", pControl );
+ pInfoTargetPickerDialog->AddActionSignalTarget( this );
+ pInfoTargetPickerDialog->DoModal( vec, pContextKeyValues );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when a sound is successfully recorded
+//-----------------------------------------------------------------------------
+void CCommentaryPropertiesPanel::OnSoundRecorded( KeyValues *pKeyValues )
+{
+ const char *pFileName = pKeyValues->GetString( "relativepath" );
+ m_pSoundFileName->SetText( pFileName );
+ UpdateCommentaryNode();
+}
+
+
+//-----------------------------------------------------------------------------
+// Used to open a particular file in perforce, and deal with all the lovely dialogs
+//-----------------------------------------------------------------------------
+void CCommentaryPropertiesPanel::OnFileSelected( KeyValues *pKeyValues )
+{
+ const char *pFileName = pKeyValues->GetString( "fullpath" );
+ if ( g_pFileSystem->FileExists( pFileName ) )
+ {
+ char pBuf[1024];
+ Q_snprintf( pBuf, sizeof(pBuf), "File %s already exists!\nRecording audio will not overwrite existing files.", pFileName );
+ vgui::MessageBox *pMessageBox = new vgui::MessageBox( "File already Exists!\n", pBuf, g_pCommEditTool );
+ pMessageBox->DoModal( );
+ return;
+ }
+
+ CSoundRecordPanel *pSoundRecordPanel = new CSoundRecordPanel( g_pCommEditTool->GetRootPanel(), "Record Commentary" );
+ pSoundRecordPanel->AddActionSignalTarget( this );
+ pSoundRecordPanel->DoModal( pFileName );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when sound recording is requested
+//-----------------------------------------------------------------------------
+void CCommentaryPropertiesPanel::RecordSound( )
+{
+ char pStartingDir[ MAX_PATH ];
+ GetModSubdirectory( "sound", pStartingDir, sizeof(pStartingDir) );
+
+ vgui::FileOpenDialog *pDialog = new vgui::FileOpenDialog( this, "Save As", false );
+ pDialog->SetTitle( "Enter New Audio File", true );
+ pDialog->SetStartDirectoryContext( "commedit_audio_record", pStartingDir );
+ pDialog->AddFilter( "*.wav", "Audio File (*.wav)", true );
+ pDialog->SetDeleteSelfOnClose( true );
+ pDialog->AddActionSignalTarget( this );
+ pDialog->DoModal( true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when buttons are clicked
+//-----------------------------------------------------------------------------
+void CCommentaryPropertiesPanel::OnCommand( const char *pCommand )
+{
+ if ( !Q_stricmp( pCommand, "PickSound" ) )
+ {
+ PickSound();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "Record" ) )
+ {
+ RecordSound();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "PickViewPosition" ) )
+ {
+ PickInfoTarget( m_pViewPosition );
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "PickViewTarget" ) )
+ {
+ PickInfoTarget( m_pViewTarget );
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "PreventMovementClicked" ) )
+ {
+ UpdateCommentaryNode();
+ return;
+ }
+
+ BaseClass::OnCommand( pCommand );
+}
+
+
diff --git a/tools/commedit/commentarypropertiespanel.h b/tools/commedit/commentarypropertiespanel.h
new file mode 100644
index 0000000..35e27e5
--- /dev/null
+++ b/tools/commedit/commentarypropertiespanel.h
@@ -0,0 +1,113 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#ifndef COMMENTARYPROPERTIESPANEL_H
+#define COMMENTARYPROPERTIESPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/editablepanel.h"
+#include "tier1/utlstring.h"
+#include "datamodel/dmehandle.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CCommEditDoc;
+class CDmeCommentaryNodeEntity;
+
+namespace vgui
+{
+ class ComboBox;
+ class Button;
+ class TextEntry;
+ class ListPanel;
+ class CheckButton;
+ class RadioButton;
+}
+
+
+//-----------------------------------------------------------------------------
+// Panel that shows all entities in the level
+//-----------------------------------------------------------------------------
+class CCommentaryPropertiesPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CCommentaryPropertiesPanel, vgui::EditablePanel );
+
+public:
+ CCommentaryPropertiesPanel( CCommEditDoc *pDoc, vgui::Panel* pParent ); // standard constructor
+
+ // Inherited from Panel
+ virtual void OnCommand( const char *pCommand );
+
+ // Sets the object to look at
+ void SetObject( CDmeCommentaryNodeEntity *pEntity );
+
+private:
+ // Populates the commentary node fields
+ void PopulateCommentaryNodeFields();
+
+ // Populates the info_target fields
+ void PopulateInfoTargetFields();
+
+ // Text to attribute...
+ void TextEntryToAttribute( vgui::TextEntry *pEntry, const char *pAttributeName );
+ void TextEntriesToVector( vgui::TextEntry *pEntry[3], const char *pAttributeName );
+
+ // Updates entity state when text fields change
+ void UpdateCommentaryNode();
+ void UpdateInfoTarget();
+
+ // Called when the audio picker button is selected
+ void PickSound();
+
+ // Called when sound recording is requested
+ void RecordSound( );
+
+ // Called when the audio picker button is selected
+ void PickInfoTarget( vgui::TextEntry *pControl );
+
+ // Messages handled
+ MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", kv );
+ MESSAGE_FUNC_PARAMS( OnSoundSelected, "SoundSelected", kv );
+ MESSAGE_FUNC_PARAMS( OnPicked, "Picked", kv );
+ MESSAGE_FUNC_PARAMS( OnFileSelected, "FileSelected", kv );
+ MESSAGE_FUNC_PARAMS( OnSoundRecorded, "SoundRecorded", kv );
+
+ CCommEditDoc *m_pDoc;
+
+ vgui::EditablePanel *m_pCommentaryNodeScroll;
+ vgui::EditablePanel *m_pInfoTargetScroll;
+ vgui::EditablePanel *m_pCommentaryNode;
+ vgui::EditablePanel *m_pInfoTarget;
+
+ vgui::TextEntry *m_pNodeName;
+ vgui::Button *m_pSoundFilePicker;
+ vgui::TextEntry *m_pSoundFileName;
+ vgui::Button *m_pRecordSound;
+ vgui::TextEntry *m_pSpeakerName;
+ vgui::TextEntry *m_pSynopsis;
+ vgui::TextEntry *m_pViewPosition;
+ vgui::Button *m_pViewPositionPicker;
+ vgui::TextEntry *m_pViewTarget;
+ vgui::Button *m_pViewTargetPicker;
+ vgui::TextEntry *m_pStartCommands;
+ vgui::TextEntry *m_pEndCommands;
+ vgui::CheckButton *m_pPreventMovement;
+ vgui::TextEntry *m_pPosition[3];
+ vgui::TextEntry *m_pOrientation[3];
+
+ vgui::TextEntry *m_pTargetName;
+ vgui::TextEntry *m_pTargetPosition[3];
+ vgui::TextEntry *m_pTargetOrientation[3];
+
+ CDmeHandle< CDmeCommentaryNodeEntity > m_hEntity;
+};
+
+
+#endif // COMMENTARYPROPERTIESPANEL_H
diff --git a/tools/commedit/dmecommentarynodeentity.cpp b/tools/commedit/dmecommentarynodeentity.cpp
new file mode 100644
index 0000000..06ae859
--- /dev/null
+++ b/tools/commedit/dmecommentarynodeentity.cpp
@@ -0,0 +1,339 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "dmecommentarynodeentity.h"
+#include "datamodel/dmelementfactoryhelper.h"
+#include "toolframework/itoolentity.h"
+#include "materialsystem/imesh.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialsystem.h"
+#include "engine/iclientleafsystem.h"
+#include "toolutils/enginetools_int.h"
+#include "commedittool.h"
+#include "KeyValues.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+#define SPHERE_RADIUS 16
+
+//-----------------------------------------------------------------------------
+// Expose this class to the scene database
+//-----------------------------------------------------------------------------
+IMPLEMENT_ELEMENT_FACTORY( DmeCommentaryNodeEntity, CDmeCommentaryNodeEntity );
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDmeCommentaryNodeEntity::OnConstruction()
+{
+ m_ClassName.InitAndSet( this, "classname", false, FATTRIB_HAS_CALLBACK );
+ m_TargetName.Init( this, "targetname" );
+ m_bIsPlaceholder.InitAndSet( this, "_placeholder", false, FATTRIB_DONTSAVE );
+ m_vecLocalOrigin.Init( this, "origin" );
+ m_vecLocalAngles.Init( this, "angles" );
+
+ // Used to make sure these aren't saved if they aren't changed
+ m_TargetName.GetAttribute()->AddFlag( FATTRIB_DONTSAVE | FATTRIB_HAS_CALLBACK );
+ m_vecLocalAngles.GetAttribute()->AddFlag( FATTRIB_DONTSAVE | FATTRIB_HAS_CALLBACK );
+
+ m_bInfoTarget = false;
+ m_bIsDirty = false;
+ m_hEngineEntity = HTOOLHANDLE_INVALID;
+
+ KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
+ pVMTKeyValues->SetString( "$basetexture", "editor/info_target" );
+ pVMTKeyValues->SetInt( "$nocull", 1 );
+ pVMTKeyValues->SetInt( "$vertexcolor", 1 );
+ pVMTKeyValues->SetInt( "$vertexalpha", 1 );
+ pVMTKeyValues->SetInt( "$no_fullbright", 1 );
+ pVMTKeyValues->SetInt( "$translucent", 1 );
+ m_InfoTargetSprite.Init( "__commentary_info_target", pVMTKeyValues );
+
+ pVMTKeyValues = new KeyValues( "UnlitGeneric" );
+ pVMTKeyValues->SetInt( "$nocull", 1 );
+ pVMTKeyValues->SetString( "$color", "{255 0 0}" );
+ pVMTKeyValues->SetInt( "$vertexalpha", 1 );
+ pVMTKeyValues->SetInt( "$no_fullbright", 1 );
+ pVMTKeyValues->SetInt( "$additive", 1 );
+ m_SelectedInfoTarget.Init( "__selected_commentary_info_target", pVMTKeyValues );
+}
+
+void CDmeCommentaryNodeEntity::OnDestruction()
+{
+ // Unhook it from the engine
+ AttachToEngineEntity( HTOOLHANDLE_INVALID );
+ m_SelectedInfoTarget.Shutdown();
+ m_InfoTargetSprite.Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// Called whem attributes change
+//-----------------------------------------------------------------------------
+void CDmeCommentaryNodeEntity::OnAttributeChanged( CDmAttribute *pAttribute )
+{
+ BaseClass::OnAttributeChanged( pAttribute );
+
+ // Once these have changed, then save them out, and don't bother calling back
+ if ( pAttribute == m_TargetName.GetAttribute() ||
+ pAttribute == m_vecLocalAngles.GetAttribute() )
+ {
+ pAttribute->RemoveFlag( FATTRIB_DONTSAVE | FATTRIB_HAS_CALLBACK );
+ return;
+ }
+
+ if ( pAttribute == m_ClassName.GetAttribute() )
+ {
+ m_bInfoTarget = !Q_strncmp( m_ClassName, "info_target", 11 );
+ if ( !Q_stricmp( m_ClassName, "point_commentary_node" ) )
+ {
+ SetModelName( "models/extras/info_speech.mdl" );
+ GetMDL()->m_flPlaybackRate = 0.0f;
+ }
+ else
+ {
+ SetModelName( NULL );
+ }
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the entity ID
+//-----------------------------------------------------------------------------
+int CDmeCommentaryNodeEntity::GetEntityId() const
+{
+ return atoi( GetName() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Mark the entity as being dirty
+//-----------------------------------------------------------------------------
+void CDmeCommentaryNodeEntity::MarkDirty( bool bDirty )
+{
+ m_bIsDirty = bDirty;
+}
+
+
+//-----------------------------------------------------------------------------
+// Is the renderable transparent?
+//-----------------------------------------------------------------------------
+bool CDmeCommentaryNodeEntity::IsTransparent( void )
+{
+ return m_bIsDirty || m_bInfoTarget || BaseClass::IsTransparent();
+}
+
+
+//-----------------------------------------------------------------------------
+// Entity Key iteration
+//-----------------------------------------------------------------------------
+bool CDmeCommentaryNodeEntity::IsEntityKey( CDmAttribute *pEntityKey )
+{
+ return pEntityKey->IsFlagSet( FATTRIB_USERDEFINED );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CDmAttribute *CDmeCommentaryNodeEntity::FirstEntityKey()
+{
+ for ( CDmAttribute *pAttribute = FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
+ {
+ if ( IsEntityKey( pAttribute ) )
+ return pAttribute;
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CDmAttribute *CDmeCommentaryNodeEntity::NextEntityKey( CDmAttribute *pEntityKey )
+{
+ if ( !pEntityKey )
+ return NULL;
+
+ for ( CDmAttribute *pAttribute = pEntityKey->NextAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
+ {
+ if ( IsEntityKey( pAttribute ) )
+ return pAttribute;
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Attach/detach from an engine entity with the same editor index
+//-----------------------------------------------------------------------------
+void CDmeCommentaryNodeEntity::AttachToEngineEntity( HTOOLHANDLE hToolHandle )
+{
+ if ( m_hEngineEntity != HTOOLHANDLE_INVALID )
+ {
+ clienttools->SetEnabled( m_hEngineEntity, true );
+ }
+ m_hEngineEntity = hToolHandle;
+ if ( m_hEngineEntity != HTOOLHANDLE_INVALID )
+ {
+ clienttools->SetEnabled( m_hEngineEntity, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Position and bounds for the model
+//-----------------------------------------------------------------------------
+const Vector &CDmeCommentaryNodeEntity::GetRenderOrigin( void )
+{
+ return m_vecLocalOrigin;
+}
+
+const QAngle &CDmeCommentaryNodeEntity::GetRenderAngles( void )
+{
+ return *(QAngle*)(&m_vecLocalAngles.Get());
+}
+
+
+//-----------------------------------------------------------------------------
+// Draws the helper for the entity
+//-----------------------------------------------------------------------------
+void CDmeCommentaryNodeEntity::DrawSprite( IMaterial *pMaterial )
+{
+ float t = 0.5f * sin( Plat_FloatTime() * M_PI / 1.0f ) + 0.5f;
+
+ CMatRenderContextPtr pRenderContext( materials );
+ pRenderContext->Bind( pMaterial );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh();
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 4, 4 );
+
+ unsigned char nBaseR = 255;
+ unsigned char nBaseG = 255;
+ unsigned char nBaseB = 255;
+ unsigned char nAlpha = m_bIsDirty ? (unsigned char)(255 * t) : 255;
+
+ meshBuilder.Position3f( -SPHERE_RADIUS, -SPHERE_RADIUS, 0.0f );
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( SPHERE_RADIUS, -SPHERE_RADIUS, 0.0f );
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( SPHERE_RADIUS, SPHERE_RADIUS, 0.0f );
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( -SPHERE_RADIUS, SPHERE_RADIUS, 0.0f );
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.FastIndex( 0 );
+ meshBuilder.FastIndex( 1 );
+ meshBuilder.FastIndex( 3 );
+ meshBuilder.FastIndex( 2 );
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+
+//-----------------------------------------------------------------------------
+// Draws the helper for the entity
+//-----------------------------------------------------------------------------
+int CDmeCommentaryNodeEntity::DrawModel( int flags )
+{
+ bool bSelected = ( g_pCommEditTool->GetCurrentEntity().Get() == this );
+ if ( !m_bInfoTarget )
+ {
+ // If we have a visible engine entity, we don't need to draw it here
+ // info targets always draw though, because they have no visible model.
+ CDisableUndoScopeGuard guard;
+ float t = 0.5f * sin( Plat_FloatTime() * M_PI / 1.0f ) + 0.5f;
+ unsigned char nAlpha = m_bIsDirty ? (unsigned char)(255 * t) : 255;
+ if ( bSelected )
+ {
+ GetMDL()->m_Color.SetColor( 255, 64, 64, nAlpha );
+ }
+ else
+ {
+ GetMDL()->m_Color.SetColor( 255, 255, 255, nAlpha );
+ }
+ return BaseClass::DrawModel( flags );
+ }
+
+ Assert( IsDrawingInEngine() );
+
+ CMatRenderContextPtr pRenderContext( materials );
+ matrix3x4_t mat;
+ VMatrix worldToCamera, cameraToWorld;
+ pRenderContext->GetMatrix( MATERIAL_VIEW, &worldToCamera );
+ MatrixInverseTR( worldToCamera, cameraToWorld );
+ MatrixCopy( cameraToWorld.As3x4(), mat );
+ MatrixSetColumn( m_vecLocalOrigin, 3, mat );
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadMatrix( mat );
+
+ pRenderContext->FogMode( MATERIAL_FOG_NONE );
+ pRenderContext->SetNumBoneWeights( 0 );
+ pRenderContext->CullMode( MATERIAL_CULLMODE_CW );
+
+ DrawSprite( m_InfoTargetSprite );
+ if ( bSelected )
+ {
+ DrawSprite( m_SelectedInfoTarget );
+ }
+
+ pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PopMatrix();
+
+ return 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Position and bounds for the model
+//-----------------------------------------------------------------------------
+void CDmeCommentaryNodeEntity::GetRenderBounds( Vector& mins, Vector& maxs )
+{
+ if ( !m_bInfoTarget )
+ {
+ BaseClass::GetRenderBounds( mins, maxs );
+ return;
+ }
+
+ mins.Init( -SPHERE_RADIUS, -SPHERE_RADIUS, -SPHERE_RADIUS );
+ maxs.Init( SPHERE_RADIUS, SPHERE_RADIUS, SPHERE_RADIUS );
+}
+
+
+//-----------------------------------------------------------------------------
+// Update renderable position
+//-----------------------------------------------------------------------------
+void CDmeCommentaryNodeEntity::SetRenderOrigin( const Vector &vecOrigin )
+{
+ m_vecLocalOrigin = vecOrigin;
+ clienttools->MarkClientRenderableDirty( this );
+}
+
+void CDmeCommentaryNodeEntity::SetRenderAngles( const QAngle &angles )
+{
+ m_vecLocalAngles = *(Vector*)&angles;
+ clienttools->MarkClientRenderableDirty( this );
+}
+
+
diff --git a/tools/commedit/dmecommentarynodeentity.h b/tools/commedit/dmecommentarynodeentity.h
new file mode 100644
index 0000000..00c7aac
--- /dev/null
+++ b/tools/commedit/dmecommentarynodeentity.h
@@ -0,0 +1,100 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Represents an entity in a VMF
+//
+//=============================================================================
+
+#ifndef DMEVMFENTITY_H
+#define DMEVMFENTITY_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "toolutils/dmemdlrenderable.h"
+#include "datamodel/dmelement.h"
+#include "toolframework/itoolentity.h"
+#include "materialsystem/MaterialSystemUtil.h"
+
+
+//-----------------------------------------------------------------------------
+// Represents an editable entity; draws its helpers
+//-----------------------------------------------------------------------------
+class CDmeCommentaryNodeEntity : public CDmeMdlRenderable<CDmElement>
+{
+ DEFINE_ELEMENT( CDmeCommentaryNodeEntity, CDmeMdlRenderable<CDmElement> );
+
+public:
+ // Inherited from CDmElement
+ virtual void OnAttributeChanged( CDmAttribute *pAttribute );
+
+public:
+ // Inherited from DmeRenderable
+ virtual const Vector &GetRenderOrigin( void );
+ virtual const QAngle &GetRenderAngles( void );
+ virtual int DrawModel( int flags );
+ virtual void GetRenderBounds( Vector& mins, Vector& maxs );
+ virtual bool IsTransparent( void );
+
+public:
+ int GetEntityId() const;
+
+ const char *GetClassName() const;
+ const char *GetTargetName() const;
+
+ bool IsPlaceholder() const;
+
+ // Entity Key iteration
+ CDmAttribute *FirstEntityKey();
+ CDmAttribute *NextEntityKey( CDmAttribute *pEntityKey );
+
+ // Attach/detach from an engine entity with the same editor index
+ void AttachToEngineEntity( HTOOLHANDLE hToolHandle );
+
+ void SetRenderOrigin( const Vector &vecOrigin );
+ void SetRenderAngles( const QAngle &angles );
+
+ void MarkDirty( bool bDirty = true );
+
+private:
+ bool IsEntityKey( CDmAttribute *pEntityKey );
+
+ // Draws the helper for the entity
+ void DrawSprite( IMaterial *pMaterial );
+
+ CDmaVar<Vector> m_vecLocalOrigin;
+ CDmaVar<Vector> m_vecLocalAngles;
+
+ CDmaString m_ClassName;
+ CDmaString m_TargetName;
+ CDmaVar<bool> m_bIsPlaceholder;
+
+ bool m_bInfoTarget;
+ bool m_bIsDirty;
+
+ // The entity it's connected to in the engine
+ HTOOLHANDLE m_hEngineEntity;
+
+ CMaterialReference m_SelectedInfoTarget;
+ CMaterialReference m_InfoTargetSprite;
+};
+
+
+//-----------------------------------------------------------------------------
+// Inline methods
+//-----------------------------------------------------------------------------
+inline const char *CDmeCommentaryNodeEntity::GetClassName() const
+{
+ return m_ClassName;
+}
+
+inline const char *CDmeCommentaryNodeEntity::GetTargetName() const
+{
+ return m_TargetName;
+}
+
+inline bool CDmeCommentaryNodeEntity::IsPlaceholder() const
+{
+ return m_bIsPlaceholder;
+}
+
+#endif // DMEVMFENTITY_H
diff --git a/tools/commedit/entityreportpanel.cpp b/tools/commedit/entityreportpanel.cpp
new file mode 100644
index 0000000..0ea1032
--- /dev/null
+++ b/tools/commedit/entityreportpanel.cpp
@@ -0,0 +1,581 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Singleton dialog that generates and presents the entity report.
+//
+//===========================================================================//
+
+#include "EntityReportPanel.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "iregistry.h"
+#include "vgui/ivgui.h"
+#include "vgui_controls/listpanel.h"
+#include "vgui_controls/textentry.h"
+#include "vgui_controls/checkbutton.h"
+#include "vgui_controls/combobox.h"
+#include "vgui_controls/radiobutton.h"
+#include "vgui_controls/messagebox.h"
+#include "commeditdoc.h"
+#include "commedittool.h"
+#include "datamodel/dmelement.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Sort by target name
+//-----------------------------------------------------------------------------
+static int __cdecl TargetNameSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ const char *string1 = item1.kv->GetString("targetname");
+ const char *string2 = item2.kv->GetString("targetname");
+ int nRetVal = Q_stricmp( string1, string2 );
+ if ( nRetVal != 0 )
+ return nRetVal;
+
+ string1 = item1.kv->GetString("classname");
+ string2 = item2.kv->GetString("classname");
+ return Q_stricmp( string1, string2 );
+}
+
+//-----------------------------------------------------------------------------
+// Sort by class name
+//-----------------------------------------------------------------------------
+static int __cdecl ClassNameSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ const char *string1 = item1.kv->GetString("classname");
+ const char *string2 = item2.kv->GetString("classname");
+ int nRetVal = Q_stricmp( string1, string2 );
+ if ( nRetVal != 0 )
+ return nRetVal;
+
+ string1 = item1.kv->GetString("targetname");
+ string2 = item2.kv->GetString("targetname");
+ return Q_stricmp( string1, string2 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CEntityReportPanel::CEntityReportPanel( CCommEditDoc *pDoc, vgui::Panel* pParent, const char *pName )
+ : BaseClass( pParent, pName ), m_pDoc( pDoc )
+{
+ m_bSuppressEntityListUpdate = false;
+ m_iFilterByType = FILTER_SHOW_EVERYTHING;
+ m_bFilterByKeyvalue = false;
+ m_bFilterByClass = false;
+ m_bFilterByHidden = false;
+ m_bFilterByKeyvalue = false;
+ m_bExact = false;
+ m_bFilterTextChanged = false;
+
+ SetPaintBackgroundEnabled( true );
+
+ m_pEntities = new vgui::ListPanel( this, "Entities" );
+ m_pEntities->AddColumnHeader( 0, "targetname", "Name", 52, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pEntities->AddColumnHeader( 1, "classname", "Class Name", 52, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pEntities->SetColumnSortable( 0, true );
+ m_pEntities->SetColumnSortable( 1, true );
+ m_pEntities->SetEmptyListText( "No Entities" );
+ // m_pEntities->SetDragEnabled( true );
+ m_pEntities->AddActionSignalTarget( this );
+ m_pEntities->SetSortFunc( 0, TargetNameSortFunc );
+ m_pEntities->SetSortFunc( 1, ClassNameSortFunc );
+ m_pEntities->SetSortColumn( 0 );
+
+ // Filtering checkboxes
+ m_pFilterByClass = new vgui::CheckButton( this, "ClassnameCheck", "" );
+ m_pFilterByClass->AddActionSignalTarget( this );
+ m_pFilterByKeyvalue = new vgui::CheckButton( this, "KeyvalueCheck", "" );
+ m_pFilterByKeyvalue->AddActionSignalTarget( this );
+ m_pFilterByHidden = new vgui::CheckButton( this, "HiddenCheck", "" );
+ m_pFilterByHidden->AddActionSignalTarget( this );
+ m_pExact = new vgui::CheckButton( this, "ExactCheck", "" );
+ m_pExact->AddActionSignalTarget( this );
+
+ // Filtering text entries
+ m_pFilterKey = new vgui::TextEntry( this, "KeyTextEntry" );
+ m_pFilterValue = new vgui::TextEntry( this, "ValueTextEntry" );
+
+ // Classname combobox
+ m_pFilterClass = new vgui::ComboBox( this, "ClassNameComboBox", 16, true );
+
+ // Filter by type radio buttons
+ m_pFilterEverything = new vgui::RadioButton( this, "EverythingRadio", "" );
+ m_pFilterPointEntities = new vgui::RadioButton( this, "PointRadio", "" );
+ m_pFilterBrushModels = new vgui::RadioButton( this, "BrushRadio", "" );
+
+ LoadControlSettings( "resource/entityreportpanel.res" );
+
+ ReadSettingsFromRegistry();
+
+ // Used for updating filter while changing text
+ ivgui()->AddTickSignal( GetVPanel(), 300 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Reads settings from registry
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::ReadSettingsFromRegistry()
+{
+ m_bSuppressEntityListUpdate = true;
+
+ const char *pKeyBase = g_pCommEditTool->GetRegistryName();
+ m_pFilterByKeyvalue->SetSelected( registry->ReadInt(pKeyBase, "FilterByKeyvalue", 0) );
+ m_pFilterByClass->SetSelected( registry->ReadInt(pKeyBase, "FilterByClass", 0) );
+ m_pFilterByHidden->SetSelected( registry->ReadInt(pKeyBase, "FilterByHidden", 1) );
+ m_pExact->SetSelected( registry->ReadInt(pKeyBase, "Exact", 0) );
+
+ m_iFilterByType = (FilterType_t)registry->ReadInt(pKeyBase, "FilterByType", FILTER_SHOW_EVERYTHING);
+ m_pFilterEverything->SetSelected( m_iFilterByType == FILTER_SHOW_EVERYTHING );
+ m_pFilterPointEntities->SetSelected( m_iFilterByType == FILTER_SHOW_POINT_ENTITIES );
+ m_pFilterBrushModels->SetSelected( m_iFilterByType == FILTER_SHOW_BRUSH_ENTITIES );
+
+ // Gotta call change functions manually since SetText doesn't post an action signal
+ const char *pValue = registry->ReadString( pKeyBase, "FilterClass", "" );
+ m_pFilterClass->SetText( pValue );
+ OnChangeFilterclass( pValue );
+
+ pValue = registry->ReadString( pKeyBase, "FilterKey", "" );
+ m_pFilterKey->SetText( pValue );
+ OnChangeFilterkey( pValue );
+
+ pValue = registry->ReadString( pKeyBase, "FilterValue", "" );
+ m_pFilterValue->SetText( pValue );
+ OnChangeFiltervalue( pValue );
+
+ m_bSuppressEntityListUpdate = false;
+ UpdateEntityList();
+}
+
+
+//-----------------------------------------------------------------------------
+// Writes settings to registry
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::SaveSettingsToRegistry()
+{
+ const char *pKeyBase = g_pCommEditTool->GetRegistryName();
+ registry->WriteInt(pKeyBase, "FilterByKeyvalue", m_bFilterByKeyvalue);
+ registry->WriteInt(pKeyBase, "FilterByClass", m_bFilterByClass);
+ registry->WriteInt(pKeyBase, "FilterByHidden", m_bFilterByHidden);
+ registry->WriteInt(pKeyBase, "FilterByType", m_iFilterByType);
+ registry->WriteInt(pKeyBase, "Exact", m_bExact);
+
+ registry->WriteString(pKeyBase, "FilterClass", m_szFilterClass);
+ registry->WriteString(pKeyBase, "FilterKey", m_szFilterKey);
+ registry->WriteString(pKeyBase, "FilterValue", m_szFilterValue);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Shows the most recent selected object in properties window
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnProperties(void)
+{
+ int iSel = m_pEntities->GetSelectedItem( 0 );
+ KeyValues *kv = m_pEntities->GetItem( iSel );
+ CDmElement *pEntity = (CDmElement *)kv->GetPtr( "entity" );
+ g_pCommEditTool->ShowEntityInEntityProperties( pEntity );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Deletes the marked objects.
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnDeleteEntities(void)
+{
+ // This is undoable
+ CUndoScopeGuard guard( g_pDataModel, "Delete Entities", "Delete Entities" );
+
+ int iSel = m_pEntities->GetSelectedItem( 0 );
+
+ //
+ // Build a list of objects to delete.
+ //
+ int nCount = m_pEntities->GetSelectedItemsCount();
+ for (int i = 0; i < nCount; i++)
+ {
+ int nItemID = m_pEntities->GetSelectedItem(i);
+ KeyValues *kv = m_pEntities->GetItem( nItemID );
+ CDmElement *pEntity = (CDmElement *)kv->GetPtr( "entity" );
+ if ( pEntity )
+ {
+ m_pDoc->DeleteCommentaryNode( pEntity );
+ }
+ }
+
+ UpdateEntityList();
+
+ // Update the list box selection.
+ if (iSel >= m_pEntities->GetItemCount())
+ {
+ iSel = m_pEntities->GetItemCount() - 1;
+ }
+ m_pEntities->SetSingleSelectedItem( iSel );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when buttons are clicked
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnCommand( const char *pCommand )
+{
+ if ( !Q_stricmp( pCommand, "delete" ) )
+ {
+ // Confirm we want to do it
+ MessageBox *pConfirm = new MessageBox( "#CommEditDeleteObjects", "#CommEditDeleteObjectsMsg", g_pCommEditTool->GetRootPanel() );
+ pConfirm->AddActionSignalTarget( this );
+ pConfirm->SetOKButtonText( "Yes" );
+ pConfirm->SetCommand( new KeyValues( "DeleteEntities" ) );
+ pConfirm->SetCancelButtonVisible( true );
+ pConfirm->SetCancelButtonText( "No" );
+ pConfirm->DoModal();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "ShowProperties" ) )
+ {
+ OnProperties();
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Call this when our settings are dirty
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::MarkDirty( bool bFilterDirty )
+{
+ float flTime = Plat_FloatTime();
+ m_bRegistrySettingsChanged = true;
+ m_flRegistryTime = flTime;
+ if ( bFilterDirty && !m_bFilterTextChanged )
+ {
+ m_bFilterTextChanged = true;
+ m_flFilterTime = flTime;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods related to filtering
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnFilterByHidden( bool bState )
+{
+ m_bFilterByHidden = bState;
+ UpdateEntityList();
+ MarkDirty( false );
+}
+
+void CEntityReportPanel::OnFilterByKeyvalue( bool bState )
+{
+ m_bFilterByKeyvalue = bState;
+ UpdateEntityList();
+ MarkDirty( false );
+
+ m_pFilterKey->SetEnabled( bState );
+ m_pFilterValue->SetEnabled( bState );
+ m_pExact->SetEnabled( bState );
+}
+
+void CEntityReportPanel::OnFilterKeyValueExact( bool bState )
+{
+ m_bExact = bState;
+ UpdateEntityList();
+ MarkDirty( false );
+}
+
+void CEntityReportPanel::OnFilterByType( FilterType_t type )
+{
+ m_iFilterByType = type;
+ UpdateEntityList();
+ MarkDirty( false );
+}
+
+void CEntityReportPanel::OnFilterByClass( bool bState )
+{
+ m_bFilterByClass = bState;
+ UpdateEntityList();
+ MarkDirty( false );
+
+ m_pFilterClass->SetEnabled( bState );
+}
+
+void CEntityReportPanel::OnChangeFilterkey( const char *pText )
+{
+ m_szFilterKey = pText;
+ MarkDirty( true );
+}
+
+void CEntityReportPanel::OnChangeFiltervalue( const char *pText )
+{
+ m_szFilterValue = pText;
+ MarkDirty( true );
+}
+
+void CEntityReportPanel::OnChangeFilterclass( const char *pText )
+{
+ m_szFilterClass = pText;
+ MarkDirty( true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Deals with all check buttons
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnTextChanged( KeyValues *kv )
+{
+ TextEntry *pPanel = (TextEntry*)kv->GetPtr( "panel", NULL );
+
+ int nLength = pPanel->GetTextLength();
+ char *pBuf = (char*)_alloca( nLength + 1 );
+ pPanel->GetText( pBuf, nLength+1 );
+
+ if ( pPanel == m_pFilterClass )
+ {
+ OnChangeFilterclass( pBuf );
+ return;
+ }
+ if ( pPanel == m_pFilterKey )
+ {
+ OnChangeFilterkey( pBuf );
+ return;
+ }
+ if ( pPanel == m_pFilterValue )
+ {
+ OnChangeFiltervalue( pBuf );
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Deals with all check buttons
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnButtonToggled( KeyValues *kv )
+{
+ Panel *pPanel = (Panel*)kv->GetPtr( "panel", NULL );
+ bool bState = kv->GetInt( "state", 0 ) != 0;
+
+ if ( pPanel == m_pFilterByClass )
+ {
+ OnFilterByClass( bState );
+ return;
+ }
+ if ( pPanel == m_pFilterByKeyvalue )
+ {
+ OnFilterByKeyvalue( bState );
+ return;
+ }
+ if ( pPanel == m_pFilterByHidden )
+ {
+ OnFilterByHidden( bState );
+ return;
+ }
+ if ( pPanel == m_pExact )
+ {
+ OnFilterKeyValueExact( bState );
+ return;
+ }
+ if ( pPanel == m_pFilterEverything )
+ {
+ OnFilterByType( FILTER_SHOW_EVERYTHING );
+ return;
+ }
+ if ( pPanel == m_pFilterPointEntities )
+ {
+ OnFilterByType( FILTER_SHOW_POINT_ENTITIES );
+ return;
+ }
+ if ( pPanel == m_pFilterBrushModels )
+ {
+ OnFilterByType( FILTER_SHOW_BRUSH_ENTITIES );
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// FIXME: Necessary because SetSelected doesn't cause a ButtonToggled message to trigger
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnCheckButtonChecked( KeyValues *kv )
+{
+ OnButtonToggled( kv );
+}
+
+void CEntityReportPanel::OnRadioButtonChecked( KeyValues *kv )
+{
+ OnButtonToggled( kv );
+}
+
+
+#if 0
+
+//-----------------------------------------------------------------------------
+// Purpose: Centers the 2D and 3D views on the selected entities.
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnGoto()
+{
+ MarkSelectedEntities();
+ m_pDoc->CenterViewsOnSelection();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::MarkSelectedEntities()
+{
+ m_pDoc->SelectObject(NULL, CMapDoc::scClear);
+
+ for(int i = 0; i < m_cEntities.GetCount(); i++)
+ {
+ if(!m_cEntities.GetSel(i))
+ continue;
+ CMapEntity *pEntity = (CMapEntity*) m_cEntities.GetItemDataPtr(i);
+ m_pDoc->SelectObject(pEntity, CMapDoc::scSelect);
+ }
+
+ m_pDoc->SelectObject(NULL, CMapDoc::scUpdateDisplay);
+}
+
+#endif
+
+void CEntityReportPanel::OnTick( )
+{
+ BaseClass::OnTick();
+
+ // check filters
+ float flTime = Plat_FloatTime();
+ if ( m_bFilterTextChanged )
+ {
+ if ( (flTime - m_flFilterTime) > 1e-3 )
+ {
+ m_bFilterTextChanged = false;
+ m_flFilterTime = flTime;
+ UpdateEntityList();
+ }
+ }
+ if ( m_bRegistrySettingsChanged )
+ {
+ if ( (flTime - m_flRegistryTime) > 1e-3 )
+ {
+ m_bRegistrySettingsChanged = false;
+ m_flRegistryTime = flTime;
+ SaveSettingsToRegistry();
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::UpdateEntityList(void)
+{
+ if ( m_bSuppressEntityListUpdate )
+ return;
+
+ m_bFilterTextChanged = false;
+
+ m_pEntities->RemoveAll();
+
+ CDmAttribute *pEntityList = m_pDoc->GetEntityList();
+ int nCount = pEntityList->Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmElement *pEntity = GetElement< CDmElement >( pEntityList->Get(i) );
+
+ const char *pClassName = pEntity->GetAttributeValueString( "classname" );
+ if ( !pClassName || !pClassName[0] )
+ {
+ pClassName = "<no class>";
+ }
+
+ KeyValues *kv = new KeyValues( "node" );
+ kv->SetString( "classname", pClassName );
+ kv->SetPtr( "entity", pEntity );
+
+ m_pEntities->AddItem( kv, 0, false, false );
+ }
+ m_pEntities->SortList();
+}
+
+
+#if 0
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::GenerateReport()
+{
+ POSITION p = pGD->Classes.GetHeadPosition();
+ CString str;
+ while(p)
+ {
+ GDclass *pc = pGD->Classes.GetNext(p);
+ if(!pc->IsBaseClass())
+ {
+ str = pc->GetName();
+ if(str != "worldspawn")
+ m_cFilterClass.AddString(str);
+ }
+ }
+
+ SetTimer(1, 500, NULL);
+
+ OnFilterbykeyvalue();
+ OnFilterbytype();
+ OnFilterbyclass();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnSelChangeEntityList()
+{
+ MarkSelectedEntities();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnDblClkEntityList()
+{
+ m_pDoc->CenterViewsOnSelection();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnOK()
+{
+ DestroyWindow();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnClose()
+{
+ DestroyWindow();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when our window is being destroyed.
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnDestroy()
+{
+ SaveToIni();
+ s_pDlg = NULL;
+ delete this;
+}
+#endif \ No newline at end of file
diff --git a/tools/foundry/DmeVMFEntity.cpp b/tools/foundry/DmeVMFEntity.cpp
new file mode 100644
index 0000000..29446ae
--- /dev/null
+++ b/tools/foundry/DmeVMFEntity.cpp
@@ -0,0 +1,246 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "DmeVMFEntity.h"
+#include "datamodel/dmelementfactoryhelper.h"
+#include "toolframework/itoolentity.h"
+#include "materialsystem/imesh.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialsystem.h"
+#include "engine/iclientleafsystem.h"
+#include "toolutils/enginetools_int.h"
+#include "foundrytool.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+#define SPHERE_RADIUS 16
+
+//-----------------------------------------------------------------------------
+// Expose this class to the scene database
+//-----------------------------------------------------------------------------
+IMPLEMENT_ELEMENT_FACTORY( DmeVMFEntity, CDmeVMFEntity );
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::OnConstruction()
+{
+ m_ClassName.Init( this, "classname" );
+ m_TargetName.Init( this, "targetname" );
+ m_bIsPlaceholder.InitAndSet( this, "_placeholder", false, FATTRIB_DONTSAVE );
+ m_vecLocalOrigin.Init( this, "origin" );
+ m_vecLocalAngles.Init( this, "angles" );
+
+ // Used to make sure these aren't saved if they aren't changed
+ m_TargetName.GetAttribute()->AddFlag( FATTRIB_DONTSAVE | FATTRIB_HAS_CALLBACK );
+ m_vecLocalAngles.GetAttribute()->AddFlag( FATTRIB_DONTSAVE | FATTRIB_HAS_CALLBACK );
+
+ m_hEngineEntity = HTOOLHANDLE_INVALID;
+
+ m_Wireframe.Init( "debug/debugwireframe", "editor" );
+}
+
+void CDmeVMFEntity::OnDestruction()
+{
+ // Unhook it from the engine
+ AttachToEngineEntity( false );
+ m_Wireframe.Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// Called whem attributes change
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::OnAttributeChanged( CDmAttribute *pAttribute )
+{
+ BaseClass::OnAttributeChanged( pAttribute );
+
+ // Once these have changed, then save them out, and don't bother calling back
+ if ( pAttribute == m_TargetName.GetAttribute() ||
+ pAttribute == m_vecLocalAngles.GetAttribute() )
+ {
+ pAttribute->RemoveFlag( FATTRIB_DONTSAVE | FATTRIB_HAS_CALLBACK );
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the entity ID
+//-----------------------------------------------------------------------------
+int CDmeVMFEntity::GetEntityId() const
+{
+ return atoi( GetName() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Entity Key iteration
+//-----------------------------------------------------------------------------
+bool CDmeVMFEntity::IsEntityKey( CDmAttribute *pEntityKey )
+{
+ return pEntityKey->IsFlagSet( FATTRIB_USERDEFINED );
+}
+
+CDmAttribute *CDmeVMFEntity::FirstEntityKey()
+{
+ for ( CDmAttribute *pAttribute = FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
+ {
+ if ( IsEntityKey( pAttribute ) )
+ return pAttribute;
+ }
+ return NULL;
+}
+
+CDmAttribute *CDmeVMFEntity::NextEntityKey( CDmAttribute *pEntityKey )
+{
+ if ( !pEntityKey )
+ return NULL;
+
+ for ( CDmAttribute *pAttribute = pEntityKey->NextAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
+ {
+ if ( IsEntityKey( pAttribute ) )
+ return pAttribute;
+ }
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Attach/detach from an engine entity with the same editor index
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::AttachToEngineEntity( bool bAttach )
+{
+ if ( !bAttach )
+ {
+ m_hEngineEntity = HTOOLHANDLE_INVALID;
+ }
+ else
+ {
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Draws the helper for the entity
+//-----------------------------------------------------------------------------
+int CDmeVMFEntity::DrawModel( int flags )
+{
+ Assert( IsDrawingInEngine() );
+
+ matrix3x4_t mat;
+ AngleMatrix( m_vecLocalAngles, m_vecLocalOrigin, mat );
+
+ CMatRenderContextPtr rc( g_pMaterialSystem->GetRenderContext() );
+
+ rc->MatrixMode( MATERIAL_MODEL );
+ rc->PushMatrix();
+ rc->LoadMatrix( mat );
+
+ int nTheta = 20, nPhi = 20;
+ float flRadius = SPHERE_RADIUS;
+ int nVertices = nTheta * nPhi;
+ int nIndices = 2 * ( nTheta + 1 ) * ( nPhi - 1 );
+
+ rc->FogMode( MATERIAL_FOG_NONE );
+ rc->SetNumBoneWeights( 0 );
+ rc->Bind( m_Wireframe );
+ rc->CullMode( MATERIAL_CULLMODE_CW );
+
+ IMesh* pMesh = rc->GetDynamicMesh();
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, nVertices, nIndices );
+
+ //
+ // Build the index buffer.
+ //
+ int i, j;
+ for ( i = 0; i < nPhi; ++i )
+ {
+ for ( j = 0; j < nTheta; ++j )
+ {
+ float u = j / ( float )(nTheta - 1);
+ float v = i / ( float )(nPhi - 1);
+ float theta = ( j != nTheta-1 ) ? 2.0f * M_PI * u : 0.0f;
+ float phi = M_PI * v;
+
+ Vector vecPos;
+ vecPos.x = flRadius * sin(phi) * cos(theta);
+ vecPos.y = flRadius * cos(phi);
+ vecPos.z = -flRadius * sin(phi) * sin(theta);
+
+ unsigned char red = (int)( u * 255.0f );
+ unsigned char green = (int)( v * 255.0f );
+ unsigned char blue = (int)( v * 255.0f );
+ unsigned char alpha = (int)( v * 255.0f );
+
+ meshBuilder.Position3fv( vecPos.Base() );
+ meshBuilder.Color4ub( red, green, blue, alpha );
+ meshBuilder.TexCoord2f( 0, u, v );
+ meshBuilder.BoneWeight( 0, 1.0f );
+ meshBuilder.BoneMatrix( 0, 0 );
+ meshBuilder.AdvanceVertex();
+ }
+ }
+
+ //
+ // Emit the triangle strips.
+ //
+ int idx = 0;
+ for ( i = 0; i < nPhi - 1; ++i )
+ {
+ for ( j = 0; j < nTheta; ++j )
+ {
+ idx = nTheta * i + j;
+
+ meshBuilder.FastIndex( idx );
+ meshBuilder.FastIndex( idx + nTheta );
+ }
+
+ //
+ // Emit a degenerate triangle to skip to the next row without
+ // a connecting triangle.
+ //
+ if ( i < nPhi - 2 )
+ {
+ meshBuilder.FastIndex( idx + 1 );
+ meshBuilder.FastIndex( idx + 1 + nTheta );
+ }
+ }
+
+ meshBuilder.End();
+ pMesh->Draw();
+
+ rc->CullMode( MATERIAL_CULLMODE_CCW );
+ rc->MatrixMode( MATERIAL_MODEL );
+ rc->PopMatrix();
+
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Position and bounds for the model
+//-----------------------------------------------------------------------------
+const Vector &CDmeVMFEntity::GetRenderOrigin( void )
+{
+ return m_vecLocalOrigin;
+}
+
+const QAngle &CDmeVMFEntity::GetRenderAngles( void )
+{
+ return m_vecLocalAngles;
+}
+
+void CDmeVMFEntity::GetRenderBounds( Vector& mins, Vector& maxs )
+{
+ mins.Init( -SPHERE_RADIUS, -SPHERE_RADIUS, -SPHERE_RADIUS );
+ maxs.Init( SPHERE_RADIUS, SPHERE_RADIUS, SPHERE_RADIUS );
+}
diff --git a/tools/foundry/DmeVMFEntity.h b/tools/foundry/DmeVMFEntity.h
new file mode 100644
index 0000000..b5388cd
--- /dev/null
+++ b/tools/foundry/DmeVMFEntity.h
@@ -0,0 +1,88 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Represents an entity in a VMF
+//
+//=============================================================================
+
+#ifndef DMEVMFENTITY_H
+#define DMEVMFENTITY_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "toolutils/dmerenderable.h"
+#include "datamodel/dmelement.h"
+#include "toolframework/itoolentity.h"
+#include "materialsystem/MaterialSystemUtil.h"
+
+
+//-----------------------------------------------------------------------------
+// Represents an editable entity; draws its helpers
+//-----------------------------------------------------------------------------
+class CDmeVMFEntity : public CDmeVisibilityControl< CDmeRenderable< CDmElement > >
+{
+ DEFINE_ELEMENT( CDmeVMFEntity, CDmeVisibilityControl< CDmeRenderable< CDmElement > > );
+
+public:
+ // Inherited from CDmElement
+ virtual void OnAttributeChanged( CDmAttribute *pAttribute );
+
+public:
+ // Inherited from DmeRenderable
+ virtual const Vector &GetRenderOrigin( void );
+ virtual const QAngle &GetRenderAngles( void );
+ virtual int DrawModel( int flags );
+ virtual void GetRenderBounds( Vector& mins, Vector& maxs );
+
+public:
+ int GetEntityId() const;
+
+ const char *GetClassName() const;
+ const char *GetTargetName() const;
+
+ bool IsPlaceholder() const;
+
+ // Entity Key iteration
+ CDmAttribute *FirstEntityKey();
+ CDmAttribute *NextEntityKey( CDmAttribute *pEntityKey );
+
+ // Attach/detach from an engine entity with the same editor index
+ void AttachToEngineEntity( bool bAttach );
+
+private:
+ bool IsEntityKey( CDmAttribute *pEntityKey );
+
+ CDmaVar<Vector> m_vecLocalOrigin;
+ CDmaVar<QAngle> m_vecLocalAngles;
+
+ CDmaString m_ClassName;
+ CDmaString m_TargetName;
+ CDmaVar<bool> m_bIsPlaceholder;
+
+ // The entity it's connected to in the engine
+ HTOOLHANDLE m_hEngineEntity;
+
+ CMaterialReference m_Wireframe;
+};
+
+
+//-----------------------------------------------------------------------------
+// Inline methods
+//-----------------------------------------------------------------------------
+inline const char *CDmeVMFEntity::GetClassName() const
+{
+ return m_ClassName;
+}
+
+inline const char *CDmeVMFEntity::GetTargetName() const
+{
+ return m_TargetName;
+}
+
+inline bool CDmeVMFEntity::IsPlaceholder() const
+{
+ return m_bIsPlaceholder;
+}
+
+
+#endif // DMEVMFENTITY_H
diff --git a/tools/foundry/entityreportpanel.cpp b/tools/foundry/entityreportpanel.cpp
new file mode 100644
index 0000000..7e3907a
--- /dev/null
+++ b/tools/foundry/entityreportpanel.cpp
@@ -0,0 +1,639 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Singleton dialog that generates and presents the entity report.
+//
+//===========================================================================//
+
+#include "EntityReportPanel.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "iregistry.h"
+#include "vgui/ivgui.h"
+#include "vgui_controls/listpanel.h"
+#include "vgui_controls/textentry.h"
+#include "vgui_controls/checkbutton.h"
+#include "vgui_controls/combobox.h"
+#include "vgui_controls/radiobutton.h"
+#include "vgui_controls/messagebox.h"
+#include "dmevmfentity.h"
+#include "foundrydoc.h"
+#include "foundrytool.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Sort by target name
+//-----------------------------------------------------------------------------
+static int __cdecl TargetNameSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ const char *string1 = item1.kv->GetString("targetname");
+ const char *string2 = item2.kv->GetString("targetname");
+ int nRetVal = Q_stricmp( string1, string2 );
+ if ( nRetVal != 0 )
+ return nRetVal;
+
+ string1 = item1.kv->GetString("classname");
+ string2 = item2.kv->GetString("classname");
+ return Q_stricmp( string1, string2 );
+}
+
+//-----------------------------------------------------------------------------
+// Sort by class name
+//-----------------------------------------------------------------------------
+static int __cdecl ClassNameSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ const char *string1 = item1.kv->GetString("classname");
+ const char *string2 = item2.kv->GetString("classname");
+ int nRetVal = Q_stricmp( string1, string2 );
+ if ( nRetVal != 0 )
+ return nRetVal;
+
+ string1 = item1.kv->GetString("targetname");
+ string2 = item2.kv->GetString("targetname");
+ return Q_stricmp( string1, string2 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CEntityReportPanel::CEntityReportPanel( CFoundryDoc *pDoc, vgui::Panel* pParent, const char *pName )
+ : BaseClass( pParent, pName ), m_pDoc( pDoc )
+{
+ m_bSuppressEntityListUpdate = false;
+ m_iFilterByType = FILTER_SHOW_EVERYTHING;
+ m_bFilterByKeyvalue = false;
+ m_bFilterByClass = false;
+ m_bFilterByHidden = false;
+ m_bFilterByKeyvalue = false;
+ m_bExact = false;
+ m_bFilterTextChanged = false;
+
+ SetPaintBackgroundEnabled( true );
+
+ m_pEntities = new vgui::ListPanel( this, "Entities" );
+ m_pEntities->AddColumnHeader( 0, "targetname", "Name", 52, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pEntities->AddColumnHeader( 1, "classname", "Class Name", 52, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pEntities->SetColumnSortable( 0, true );
+ m_pEntities->SetColumnSortable( 1, true );
+ m_pEntities->SetEmptyListText( "No Entities" );
+ // m_pEntities->SetDragEnabled( true );
+ m_pEntities->AddActionSignalTarget( this );
+ m_pEntities->SetSortFunc( 0, TargetNameSortFunc );
+ m_pEntities->SetSortFunc( 1, ClassNameSortFunc );
+ m_pEntities->SetSortColumn( 0 );
+
+ // Filtering checkboxes
+ m_pFilterByClass = new vgui::CheckButton( this, "ClassnameCheck", "" );
+ m_pFilterByClass->AddActionSignalTarget( this );
+ m_pFilterByKeyvalue = new vgui::CheckButton( this, "KeyvalueCheck", "" );
+ m_pFilterByKeyvalue->AddActionSignalTarget( this );
+ m_pFilterByHidden = new vgui::CheckButton( this, "HiddenCheck", "" );
+ m_pFilterByHidden->AddActionSignalTarget( this );
+ m_pExact = new vgui::CheckButton( this, "ExactCheck", "" );
+ m_pExact->AddActionSignalTarget( this );
+
+ // Filtering text entries
+ m_pFilterKey = new vgui::TextEntry( this, "KeyTextEntry" );
+ m_pFilterValue = new vgui::TextEntry( this, "ValueTextEntry" );
+
+ // Classname combobox
+ m_pFilterClass = new vgui::ComboBox( this, "ClassNameComboBox", 16, true );
+
+ // Filter by type radio buttons
+ m_pFilterEverything = new vgui::RadioButton( this, "EverythingRadio", "" );
+ m_pFilterPointEntities = new vgui::RadioButton( this, "PointRadio", "" );
+ m_pFilterBrushModels = new vgui::RadioButton( this, "BrushRadio", "" );
+
+ LoadControlSettings( "resource/entityreportpanel.res" );
+
+ ReadSettingsFromRegistry();
+
+ // Used for updating filter while changing text
+ ivgui()->AddTickSignal( GetVPanel(), 300 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Reads settings from registry
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::ReadSettingsFromRegistry()
+{
+ m_bSuppressEntityListUpdate = true;
+
+ const char *pKeyBase = g_pFoundryTool->GetRegistryName();
+ m_pFilterByKeyvalue->SetSelected( registry->ReadInt(pKeyBase, "FilterByKeyvalue", 0) );
+ m_pFilterByClass->SetSelected( registry->ReadInt(pKeyBase, "FilterByClass", 0) );
+ m_pFilterByHidden->SetSelected( registry->ReadInt(pKeyBase, "FilterByHidden", 1) );
+ m_pExact->SetSelected( registry->ReadInt(pKeyBase, "Exact", 0) );
+
+ m_iFilterByType = (FilterType_t)registry->ReadInt(pKeyBase, "FilterByType", FILTER_SHOW_EVERYTHING);
+ m_pFilterEverything->SetSelected( m_iFilterByType == FILTER_SHOW_EVERYTHING );
+ m_pFilterPointEntities->SetSelected( m_iFilterByType == FILTER_SHOW_POINT_ENTITIES );
+ m_pFilterBrushModels->SetSelected( m_iFilterByType == FILTER_SHOW_BRUSH_ENTITIES );
+
+ // Gotta call change functions manually since SetText doesn't post an action signal
+ const char *pValue = registry->ReadString( pKeyBase, "FilterClass", "" );
+ m_pFilterClass->SetText( pValue );
+ OnChangeFilterclass( pValue );
+
+ pValue = registry->ReadString( pKeyBase, "FilterKey", "" );
+ m_pFilterKey->SetText( pValue );
+ OnChangeFilterkey( pValue );
+
+ pValue = registry->ReadString( pKeyBase, "FilterValue", "" );
+ m_pFilterValue->SetText( pValue );
+ OnChangeFiltervalue( pValue );
+
+ m_bSuppressEntityListUpdate = false;
+ UpdateEntityList();
+}
+
+
+//-----------------------------------------------------------------------------
+// Writes settings to registry
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::SaveSettingsToRegistry()
+{
+ const char *pKeyBase = g_pFoundryTool->GetRegistryName();
+ registry->WriteInt(pKeyBase, "FilterByKeyvalue", m_bFilterByKeyvalue);
+ registry->WriteInt(pKeyBase, "FilterByClass", m_bFilterByClass);
+ registry->WriteInt(pKeyBase, "FilterByHidden", m_bFilterByHidden);
+ registry->WriteInt(pKeyBase, "FilterByType", m_iFilterByType);
+ registry->WriteInt(pKeyBase, "Exact", m_bExact);
+
+ registry->WriteString(pKeyBase, "FilterClass", m_szFilterClass);
+ registry->WriteString(pKeyBase, "FilterKey", m_szFilterKey);
+ registry->WriteString(pKeyBase, "FilterValue", m_szFilterValue);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Shows the most recent selected object in properties window
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnProperties(void)
+{
+ int iSel = m_pEntities->GetSelectedItem( 0 );
+ KeyValues *kv = m_pEntities->GetItem( iSel );
+ CDmeVMFEntity *pEntity = (CDmeVMFEntity *)kv->GetPtr( "entity" );
+ g_pFoundryTool->ShowEntityInEntityProperties( pEntity );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Deletes the marked objects.
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnDeleteEntities(void)
+{
+ // This is undoable
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Delete Entities", "Delete Entities" );
+
+ int iSel = m_pEntities->GetSelectedItem( 0 );
+
+ //
+ // Build a list of objects to delete.
+ //
+ int nCount = m_pEntities->GetSelectedItemsCount();
+ for (int i = 0; i < nCount; i++)
+ {
+ int nItemID = m_pEntities->GetSelectedItem(i);
+ KeyValues *kv = m_pEntities->GetItem( nItemID );
+ CDmeVMFEntity *pEntity = (CDmeVMFEntity *)kv->GetPtr( "entity" );
+ if ( pEntity )
+ {
+ m_pDoc->DeleteEntity( pEntity );
+ }
+ }
+
+ guard.Release();
+
+ UpdateEntityList();
+
+ // Update the list box selection.
+ if (iSel >= m_pEntities->GetItemCount())
+ {
+ iSel = m_pEntities->GetItemCount() - 1;
+ }
+ m_pEntities->SetSingleSelectedItem( iSel );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when buttons are clicked
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnCommand( const char *pCommand )
+{
+ if ( !Q_stricmp( pCommand, "delete" ) )
+ {
+ // Confirm we want to do it
+ MessageBox *pConfirm = new MessageBox( "#FoundryDeleteObjects", "#FoundryDeleteObjectsMsg", g_pFoundryTool->GetRootPanel() );
+ pConfirm->AddActionSignalTarget( this );
+ pConfirm->SetOKButtonText( "Yes" );
+ pConfirm->SetCommand( new KeyValues( "DeleteEntities" ) );
+ pConfirm->SetCancelButtonVisible( true );
+ pConfirm->SetCancelButtonText( "No" );
+ pConfirm->DoModal();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "ShowProperties" ) )
+ {
+ OnProperties();
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Call this when our settings are dirty
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::MarkDirty( bool bFilterDirty )
+{
+ float flTime = Plat_FloatTime();
+ m_bRegistrySettingsChanged = true;
+ m_flRegistryTime = flTime;
+ if ( bFilterDirty && !m_bFilterTextChanged )
+ {
+ m_bFilterTextChanged = true;
+ m_flFilterTime = flTime;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods related to filtering
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnFilterByHidden( bool bState )
+{
+ m_bFilterByHidden = bState;
+ UpdateEntityList();
+ MarkDirty( false );
+}
+
+void CEntityReportPanel::OnFilterByKeyvalue( bool bState )
+{
+ m_bFilterByKeyvalue = bState;
+ UpdateEntityList();
+ MarkDirty( false );
+
+ m_pFilterKey->SetEnabled( bState );
+ m_pFilterValue->SetEnabled( bState );
+ m_pExact->SetEnabled( bState );
+}
+
+void CEntityReportPanel::OnFilterKeyValueExact( bool bState )
+{
+ m_bExact = bState;
+ UpdateEntityList();
+ MarkDirty( false );
+}
+
+void CEntityReportPanel::OnFilterByType( FilterType_t type )
+{
+ m_iFilterByType = type;
+ UpdateEntityList();
+ MarkDirty( false );
+}
+
+void CEntityReportPanel::OnFilterByClass( bool bState )
+{
+ m_bFilterByClass = bState;
+ UpdateEntityList();
+ MarkDirty( false );
+
+ m_pFilterClass->SetEnabled( bState );
+}
+
+void CEntityReportPanel::OnChangeFilterkey( const char *pText )
+{
+ m_szFilterKey = pText;
+ MarkDirty( true );
+}
+
+void CEntityReportPanel::OnChangeFiltervalue( const char *pText )
+{
+ m_szFilterValue = pText;
+ MarkDirty( true );
+}
+
+void CEntityReportPanel::OnChangeFilterclass( const char *pText )
+{
+ m_szFilterClass = pText;
+ MarkDirty( true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Deals with all check buttons
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnTextChanged( KeyValues *kv )
+{
+ TextEntry *pPanel = (TextEntry*)kv->GetPtr( "panel", NULL );
+
+ int nLength = pPanel->GetTextLength();
+ char *pBuf = (char*)_alloca( nLength + 1 );
+ pPanel->GetText( pBuf, nLength+1 );
+
+ if ( pPanel == m_pFilterClass )
+ {
+ OnChangeFilterclass( pBuf );
+ return;
+ }
+ if ( pPanel == m_pFilterKey )
+ {
+ OnChangeFilterkey( pBuf );
+ return;
+ }
+ if ( pPanel == m_pFilterValue )
+ {
+ OnChangeFiltervalue( pBuf );
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Deals with all check buttons
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnButtonToggled( KeyValues *kv )
+{
+ Panel *pPanel = (Panel*)kv->GetPtr( "panel", NULL );
+ bool bState = kv->GetInt( "state", 0 ) != 0;
+
+ if ( pPanel == m_pFilterByClass )
+ {
+ OnFilterByClass( bState );
+ return;
+ }
+ if ( pPanel == m_pFilterByKeyvalue )
+ {
+ OnFilterByKeyvalue( bState );
+ return;
+ }
+ if ( pPanel == m_pFilterByHidden )
+ {
+ OnFilterByHidden( bState );
+ return;
+ }
+ if ( pPanel == m_pExact )
+ {
+ OnFilterKeyValueExact( bState );
+ return;
+ }
+ if ( pPanel == m_pFilterEverything )
+ {
+ OnFilterByType( FILTER_SHOW_EVERYTHING );
+ return;
+ }
+ if ( pPanel == m_pFilterPointEntities )
+ {
+ OnFilterByType( FILTER_SHOW_POINT_ENTITIES );
+ return;
+ }
+ if ( pPanel == m_pFilterBrushModels )
+ {
+ OnFilterByType( FILTER_SHOW_BRUSH_ENTITIES );
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// FIXME: Necessary because SetSelected doesn't cause a ButtonToggled message to trigger
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnCheckButtonChecked( KeyValues *kv )
+{
+ OnButtonToggled( kv );
+}
+
+void CEntityReportPanel::OnRadioButtonChecked( KeyValues *kv )
+{
+ OnButtonToggled( kv );
+}
+
+
+#if 0
+
+//-----------------------------------------------------------------------------
+// Purpose: Centers the 2D and 3D views on the selected entities.
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnGoto()
+{
+ MarkSelectedEntities();
+ m_pDoc->CenterViewsOnSelection();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::MarkSelectedEntities()
+{
+ m_pDoc->SelectObject(NULL, CMapDoc::scClear);
+
+ for(int i = 0; i < m_cEntities.GetCount(); i++)
+ {
+ if(!m_cEntities.GetSel(i))
+ continue;
+ CMapEntity *pEntity = (CMapEntity*) m_cEntities.GetItemDataPtr(i);
+ m_pDoc->SelectObject(pEntity, CMapDoc::scSelect);
+ }
+
+ m_pDoc->SelectObject(NULL, CMapDoc::scUpdateDisplay);
+}
+
+#endif
+
+void CEntityReportPanel::OnTick( )
+{
+ BaseClass::OnTick();
+
+ // check filters
+ float flTime = Plat_FloatTime();
+ if ( m_bFilterTextChanged )
+ {
+ if ( (flTime - m_flFilterTime) > 1e-3 )
+ {
+ m_bFilterTextChanged = false;
+ m_flFilterTime = flTime;
+ UpdateEntityList();
+ }
+ }
+ if ( m_bRegistrySettingsChanged )
+ {
+ if ( (flTime - m_flRegistryTime) > 1e-3 )
+ {
+ m_bRegistrySettingsChanged = false;
+ m_flRegistryTime = flTime;
+ SaveSettingsToRegistry();
+ }
+ }
+}
+
+bool CEntityReportPanel::ShouldAddEntityToList( CDmeVMFEntity *pEntity )
+{
+ // nope.
+ if ( !m_bFilterByHidden && !pEntity->IsVisible() )
+ return false;
+
+ /*
+ if (!pDlg->m_pDoc->selection.IsEmpty() && !pEntity->IsSelected())
+ return true;
+ */
+
+ if ( m_iFilterByType == FILTER_SHOW_POINT_ENTITIES && pEntity->IsPlaceholder() )
+ return false;
+
+ if ( m_iFilterByType == FILTER_SHOW_BRUSH_ENTITIES && !pEntity->IsPlaceholder() )
+ return false;
+
+ const char* pClassName = pEntity->GetClassName();
+
+ if ( m_bFilterByClass )
+ {
+ if ( !m_szFilterClass.IsEmpty() )
+ {
+ if ( !Q_stristr( pClassName, m_szFilterClass ) )
+ return false;
+ }
+ }
+
+ if ( !m_bFilterByKeyvalue || m_szFilterValue.IsEmpty() )
+ return true;
+
+ CUtlBuffer buf( 256, 0, CUtlBuffer::TEXT_BUFFER );
+ for ( CDmAttribute *pKey = pEntity->FirstEntityKey(); pKey; pKey = pEntity->NextEntityKey( pKey ) )
+ {
+ // first, check key
+ if ( m_szFilterKey.IsEmpty() || !Q_stricmp( m_szFilterKey, pKey->GetName() ) )
+ {
+ // now, check value (as a string)
+ buf.Clear();
+ pKey->Serialize( buf );
+ const char *pValue = (const char*)buf.Base();
+ if ( (!m_bExact && Q_stristr( pValue, m_szFilterValue ) ) || !Q_stricmp( pValue, m_szFilterValue ) )
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::UpdateEntityList(void)
+{
+ if ( m_bSuppressEntityListUpdate )
+ return;
+
+ m_bFilterTextChanged = false;
+
+ m_pEntities->RemoveAll();
+
+ const CDmrElementArray<CDmElement> entityList( m_pDoc->GetEntityList() );
+ int nCount = entityList.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeVMFEntity *pEntity = CastElement<CDmeVMFEntity>( entityList[i] );
+ if ( ShouldAddEntityToList( pEntity ) )
+ {
+ const char *pClassName = pEntity->GetClassName( );
+ const char *pTargetName = pEntity->GetTargetName( );
+ if ( !pTargetName || !pTargetName[0] )
+ {
+ pTargetName = "<no name>";
+ }
+ if ( !pClassName || !pClassName[0] )
+ {
+ pClassName = "<no class>";
+ }
+
+ KeyValues *kv = new KeyValues( "node", "targetname", pTargetName );
+ kv->SetString( "classname", pClassName );
+ kv->SetPtr( "entity", pEntity );
+
+ m_pEntities->AddItem( kv, 0, false, false );
+ }
+ }
+ m_pEntities->SortList();
+}
+
+
+#if 0
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::GenerateReport()
+{
+ POSITION p = pGD->Classes.GetHeadPosition();
+ CString str;
+ while(p)
+ {
+ GDclass *pc = pGD->Classes.GetNext(p);
+ if(!pc->IsBaseClass())
+ {
+ str = pc->GetName();
+ if(str != "worldspawn")
+ m_cFilterClass.AddString(str);
+ }
+ }
+
+ SetTimer(1, 500, NULL);
+
+ OnFilterbykeyvalue();
+ OnFilterbytype();
+ OnFilterbyclass();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnSelChangeEntityList()
+{
+ MarkSelectedEntities();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnDblClkEntityList()
+{
+ m_pDoc->CenterViewsOnSelection();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnOK()
+{
+ DestroyWindow();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnClose()
+{
+ DestroyWindow();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when our window is being destroyed.
+//-----------------------------------------------------------------------------
+void CEntityReportPanel::OnDestroy()
+{
+ SaveToIni();
+ s_pDlg = NULL;
+ delete this;
+}
+#endif \ No newline at end of file
diff --git a/tools/foundry/entityreportpanel.h b/tools/foundry/entityreportpanel.h
new file mode 100644
index 0000000..2b72ff8
--- /dev/null
+++ b/tools/foundry/entityreportpanel.h
@@ -0,0 +1,122 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#ifndef ENTITYREPORTPANEL_H
+#define ENTITYREPORTPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/editablepanel.h"
+#include "tier1/utlstring.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CFoundryDoc;
+class CDmeVMFEntity;
+
+namespace vgui
+{
+ class ComboBox;
+ class Button;
+ class TextEntry;
+ class ListPanel;
+ class CheckButton;
+ class RadioButton;
+}
+
+
+//-----------------------------------------------------------------------------
+// Panel that shows all entities in the level
+//-----------------------------------------------------------------------------
+class CEntityReportPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CEntityReportPanel, vgui::EditablePanel );
+
+public:
+ CEntityReportPanel( CFoundryDoc *pDoc, vgui::Panel* pParent, const char *pName ); // standard constructor
+
+// Inherited from Panel
+ virtual void OnTick();
+ virtual void OnCommand( const char *pCommand );
+
+private:
+ enum FilterType_t
+ {
+ FILTER_SHOW_EVERYTHING = 0,
+ FILTER_SHOW_POINT_ENTITIES = 1,
+ FILTER_SHOW_BRUSH_ENTITIES = 2
+ };
+
+ // Messages handled
+ MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", kv );
+ MESSAGE_FUNC_PARAMS( OnButtonToggled, "ButtonToggled", kv );
+ MESSAGE_FUNC( OnDeleteEntities, "DeleteEntities" );
+
+ // FIXME: Necessary because SetSelected doesn't cause a ButtonToggled message to trigger
+ MESSAGE_FUNC_PARAMS( OnCheckButtonChecked, "CheckButtonChecked", kv );
+ MESSAGE_FUNC_PARAMS( OnRadioButtonChecked, "RadioButtonChecked", kv );
+
+ // Methods related to filtering
+ void OnFilterByHidden( bool bState );
+ void OnFilterByKeyvalue( bool bState );
+ void OnFilterByClass( bool bState );
+ void OnFilterKeyValueExact( bool bState );
+ void OnFilterByType( FilterType_t type );
+ void OnChangeFilterkey( const char *pText );
+ void OnChangeFiltervalue( const char *pText );
+ void OnChangeFilterclass( const char *pText );
+
+ // Methods related to updating the listpanel
+ void UpdateEntityList();
+ bool ShouldAddEntityToList( CDmeVMFEntity *pEntity );
+
+ // Methods related to saving settings
+ void ReadSettingsFromRegistry();
+ void SaveSettingsToRegistry();
+
+ // Call this when our settings are dirty
+ void MarkDirty( bool bFilterDirty );
+
+ // Shows the most recent selected object in properties window
+ void OnProperties();
+
+ CFoundryDoc *m_pDoc;
+ FilterType_t m_iFilterByType;
+ bool m_bFilterByClass;
+ bool m_bFilterByHidden;
+ bool m_bFilterByKeyvalue;
+ bool m_bExact;
+ bool m_bSuppressEntityListUpdate;
+
+ CUtlString m_szFilterKey;
+ CUtlString m_szFilterValue;
+ CUtlString m_szFilterClass;
+
+ bool m_bFilterTextChanged;
+ float m_flFilterTime;
+
+ bool m_bRegistrySettingsChanged;
+ float m_flRegistryTime;
+
+ vgui::CheckButton *m_pExact;
+ vgui::ComboBox *m_pFilterClass;
+ vgui::CheckButton *m_pFilterByClass;
+ vgui::ListPanel *m_pEntities;
+ vgui::TextEntry *m_pFilterKey;
+ vgui::TextEntry *m_pFilterValue;
+ vgui::CheckButton *m_pFilterByKeyvalue;
+ vgui::CheckButton *m_pFilterByHidden;
+
+ vgui::RadioButton *m_pFilterEverything;
+ vgui::RadioButton *m_pFilterPointEntities;
+ vgui::RadioButton *m_pFilterBrushModels;
+};
+
+
+#endif // ENTITYREPORTPANEL_H
diff --git a/tools/foundry/foundry.vpc b/tools/foundry/foundry.vpc
new file mode 100644
index 0000000..9d211ac
--- /dev/null
+++ b/tools/foundry/foundry.vpc
@@ -0,0 +1,67 @@
+//-----------------------------------------------------------------------------
+// FOUNDRY.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin\tools"
+
+$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE,.\,$SRCDIR\game\shared"
+ $PreprocessorDefinitions "$BASE;FOUNDRY_EXPORTS"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "$BASE Psapi.lib"
+ }
+}
+
+$Project "foundry"
+{
+ $Folder "Source Files"
+ {
+ $File "DmeVMFEntity.cpp"
+ $File "DmeVMFEntity.h"
+ $File "entityreportpanel.cpp"
+ $File "entityreportpanel.h"
+ $File "foundrydoc.cpp"
+ $File "foundrytool.cpp"
+ $File "$SRCDIR\public\interpolatortypes.cpp"
+ $File "$SRCDIR\public\registry.cpp"
+ $File "$SRCDIR\public\vgui_controls\vgui_controls.cpp"
+ }
+
+ $Folder "Header Files"
+ {
+ $File "foundrydoc.h"
+ $File "foundrytool.h"
+ }
+
+ $Folder "Public Header Files"
+ {
+ $File "$SRCDIR\public\mathlib\mathlib.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib datamodel
+ $Lib dmxloader
+ $Lib dme_controls
+ $Lib dmserializers
+ $Lib mathlib
+ $Lib matsys_controls
+ $Lib movieobjects
+ $Lib sfmobjects
+ $Lib tier2
+ $Lib tier3
+ $Lib toolutils
+ $Lib vgui_controls
+ }
+}
diff --git a/tools/foundry/foundrydoc.cpp b/tools/foundry/foundrydoc.cpp
new file mode 100644
index 0000000..9d3b5d1
--- /dev/null
+++ b/tools/foundry/foundrydoc.cpp
@@ -0,0 +1,345 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "foundrydoc.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "datamodel/dmelement.h"
+#include "toolutils/enginetools_int.h"
+#include "filesystem.h"
+#include "foundrytool.h"
+#include "toolframework/ienginetool.h"
+#include "dmevmfentity.h"
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CFoundryDoc::CFoundryDoc( IFoundryDocCallback *pCallback ) : m_pCallback( pCallback )
+{
+ m_hRoot = NULL;
+ m_pBSPFileName[0] = 0;
+ m_pVMFFileName[0] = 0;
+ m_bDirty = false;
+ g_pDataModel->InstallNotificationCallback( this );
+}
+
+CFoundryDoc::~CFoundryDoc()
+{
+ g_pDataModel->RemoveNotificationCallback( this );
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from INotifyUI
+//-----------------------------------------------------------------------------
+void CFoundryDoc::NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ OnDataChanged( pReason, nNotifySource, nNotifyFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the file name
+//-----------------------------------------------------------------------------
+const char *CFoundryDoc::GetBSPFileName()
+{
+ return m_pBSPFileName;
+}
+
+const char *CFoundryDoc::GetVMFFileName()
+{
+ return m_pVMFFileName;
+}
+
+void CFoundryDoc::SetVMFFileName( const char *pFileName )
+{
+ Q_strncpy( m_pVMFFileName, pFileName, sizeof( m_pVMFFileName ) );
+ Q_FixSlashes( m_pVMFFileName );
+ SetDirty( true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Dirty bits
+//-----------------------------------------------------------------------------
+void CFoundryDoc::SetDirty( bool bDirty )
+{
+ m_bDirty = bDirty;
+}
+
+bool CFoundryDoc::IsDirty() const
+{
+ return m_bDirty;
+}
+
+
+//-----------------------------------------------------------------------------
+// Saves/loads from file
+//-----------------------------------------------------------------------------
+bool CFoundryDoc::LoadFromFile( const char *pFileName )
+{
+ Assert( !m_hRoot.Get() );
+
+ // This is not undoable
+ CAppDisableUndoScopeGuard guard( "CFoundryDoc::LoadFromFile", 0 );
+ SetDirty( false );
+
+ if ( !pFileName[0] )
+ return false;
+
+ // Store the BSP file name
+ Q_strncpy( m_pBSPFileName, pFileName, sizeof( m_pBSPFileName ) );
+
+ // Construct VMF file name from the BSP
+ const char *pGame = Q_stristr( pFileName, "\\game\\" );
+ if ( !pGame )
+ return false;
+
+ // Compute the map name
+ char mapname[ 256 ];
+ const char *pMaps = Q_stristr( pFileName, "\\maps\\" );
+ if ( !pMaps )
+ return false;
+
+ Q_strncpy( mapname, pMaps + 6, sizeof( mapname ) );
+
+ int nLen = (int)( (size_t)pGame - (size_t)pFileName ) + 1;
+ Q_strncpy( m_pVMFFileName, pFileName, nLen );
+ Q_strncat( m_pVMFFileName, "\\content\\", sizeof(m_pVMFFileName) );
+ Q_strncat( m_pVMFFileName, pGame + 6, sizeof(m_pVMFFileName) );
+ Q_SetExtension( m_pVMFFileName, ".vmf", sizeof(m_pVMFFileName) );
+
+ CDmElement *pVMF = NULL;
+ if ( g_pDataModel->RestoreFromFile( m_pVMFFileName, NULL, "vmf", &pVMF ) == DMFILEID_INVALID )
+ {
+ m_pBSPFileName[0] = 0;
+ m_pVMFFileName[0] = 0;
+ return false;
+ }
+
+ m_hRoot = pVMF;
+
+ guard.Release();
+ SetDirty( false );
+
+ char cmd[ 256 ];
+ Q_snprintf( cmd, sizeof( cmd ), "disconnect; map %s\n", mapname );
+ enginetools->Command( cmd );
+ enginetools->Execute( );
+
+ return true;
+}
+
+void CFoundryDoc::SaveToFile( )
+{
+ if ( m_hRoot.Get() && m_pVMFFileName && m_pVMFFileName[0] )
+ {
+ g_pDataModel->SaveToFile( m_pVMFFileName, NULL, "keyvalues", "vmf", m_hRoot );
+ }
+
+ SetDirty( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the root object
+//-----------------------------------------------------------------------------
+CDmElement *CFoundryDoc::GetRootObject()
+{
+ return m_hRoot;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the entity list
+//-----------------------------------------------------------------------------
+CDmAttribute *CFoundryDoc::GetEntityList()
+{
+ return m_hRoot ? m_hRoot->GetAttribute( "entities", AT_ELEMENT_ARRAY ) : NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Deletes an entity
+//-----------------------------------------------------------------------------
+void CFoundryDoc::DeleteEntity( CDmeVMFEntity *pEntity )
+{
+ CDmrElementArray<> entities( GetEntityList() );
+ if ( !entities.IsValid() )
+ return;
+
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ if ( pEntity == CastElement< CDmeVMFEntity >( entities[i] ) )
+ {
+ entities.FastRemove( i );
+ return;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when data changes
+//-----------------------------------------------------------------------------
+void CFoundryDoc::OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ SetDirty( nNotifyFlags & NOTIFY_SETDIRTYFLAG ? true : false );
+ m_pCallback->OnDocChanged( pReason, nNotifySource, nNotifyFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// List of all entity classnames to copy over from the original block
+//-----------------------------------------------------------------------------
+static const char *s_pUseOriginalClasses[] =
+{
+ "worldspawn",
+ "func_occluder",
+ NULL
+};
+
+
+//-----------------------------------------------------------------------------
+// Always copy the worldspawn and other entities that had data built into them by VBSP out
+//-----------------------------------------------------------------------------
+void CFoundryDoc::AddOriginalEntities( CUtlBuffer &entityBuf, const char *pActualEntityData )
+{
+ while ( *pActualEntityData )
+ {
+ pActualEntityData = strchr( pActualEntityData, '{' );
+ if ( !pActualEntityData )
+ break;
+
+ const char *pBlockStart = pActualEntityData;
+
+ pActualEntityData = strstr( pActualEntityData, "\"classname\"" );
+ if ( !pActualEntityData )
+ break;
+
+ // Skip "classname"
+ pActualEntityData += 11;
+
+ pActualEntityData = strchr( pActualEntityData, '\"' );
+ if ( !pActualEntityData )
+ break;
+
+ // Skip "
+ ++pActualEntityData;
+
+ char pClassName[512];
+ int j = 0;
+ while (*pActualEntityData != 0 && *pActualEntityData != '\"' )
+ {
+ pClassName[j++] = *pActualEntityData++;
+ }
+ pClassName[j] = 0;
+
+ pActualEntityData = strchr( pActualEntityData, '}' );
+ if ( !pActualEntityData )
+ break;
+
+ // Skip }
+ ++pActualEntityData;
+
+ for ( int i = 0; s_pUseOriginalClasses[i]; ++i )
+ {
+ if ( !Q_stricmp( pClassName, s_pUseOriginalClasses[i] ) )
+ {
+ // Found one we need to keep, add it to the buffer
+ int nBytes = (int)( (size_t)pActualEntityData - (size_t)pBlockStart );
+ entityBuf.Put( pBlockStart, nBytes );
+ entityBuf.PutChar( '\n' );
+ break;
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Copy in other entities from the editable VMF
+//-----------------------------------------------------------------------------
+void CFoundryDoc::AddVMFEntities( CUtlBuffer &entityBuf, const char *pActualEntityData )
+{
+ const CDmrElementArray<CDmElement> entityArray( m_hRoot, "entities" );
+ if ( !entityArray.IsValid() )
+ return;
+
+ int nCount = entityArray.Count();
+ for ( int iEntity = 0; iEntity < nCount; ++iEntity )
+ {
+ CDmElement *pEntity = entityArray[iEntity];
+ const char *pClassName = pEntity->GetValueString( "classname" );
+ if ( !pClassName || !pClassName[0] )
+ continue;
+
+ // Don't spawn those classes we grab from the actual compiled map
+ bool bDontUse = false;
+ for ( int i = 0; s_pUseOriginalClasses[i]; ++i )
+ {
+ if ( !Q_stricmp( pClassName, s_pUseOriginalClasses[i] ) )
+ {
+ bDontUse = true;
+ break;
+ }
+ }
+
+ if ( bDontUse )
+ continue;
+
+ entityBuf.PutString( "{\n" );
+ entityBuf.Printf( "\"id\" \"%d\"\n", atol( pEntity->GetName() ) );
+
+ for( CDmAttribute *pAttribute = pEntity->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
+ {
+ if ( pAttribute->IsFlagSet( FATTRIB_STANDARD ) )
+ continue;
+
+ if ( IsArrayType( pAttribute->GetType() ) )
+ continue;
+
+ if ( !Q_stricmp( pAttribute->GetName(), "editorType" ) || !Q_stricmp( pAttribute->GetName(), "editor" ) )
+ continue;
+
+ entityBuf.Printf( "\"%s\" ", pAttribute->GetName() );
+
+ // FIXME: Set up standard delimiters
+ entityBuf.PutChar( '\"' );
+ pAttribute->Serialize( entityBuf );
+ entityBuf.PutString( "\"\n" );
+ }
+
+ entityBuf.PutString( "}\n" );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Create a text block the engine can parse containing the entity data to spawn
+//-----------------------------------------------------------------------------
+const char* CFoundryDoc::GenerateEntityData( const char *pActualEntityData )
+{
+ if ( !m_hRoot.Get() )
+ return pActualEntityData;
+
+ // Contains the text block the engine can parse containing the entity data to spawn
+ static CUtlBuffer entityBuf( 2048, 2048, CUtlBuffer::TEXT_BUFFER );
+ entityBuf.Clear();
+
+ // Always copy the worldspawn and other entities that had data built into them by VBSP out
+ AddOriginalEntities( entityBuf, pActualEntityData );
+
+ // Copy in other entities from the editable VMF
+ AddVMFEntities( entityBuf, pActualEntityData );
+
+ return (const char*)entityBuf.Base();
+}
+
diff --git a/tools/foundry/foundrydoc.h b/tools/foundry/foundrydoc.h
new file mode 100644
index 0000000..73a5144
--- /dev/null
+++ b/tools/foundry/foundrydoc.h
@@ -0,0 +1,83 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef FOUNDRYDOC_H
+#define FOUNDRYDOC_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "dme_controls/inotifyui.h"
+#include "datamodel/dmehandle.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class IFoundryDocCallback;
+class CDmeVMFEntity;
+
+
+//-----------------------------------------------------------------------------
+// Contains all editable state
+//-----------------------------------------------------------------------------
+class CFoundryDoc : public IDmNotify
+{
+public:
+ CFoundryDoc( IFoundryDocCallback *pCallback );
+ ~CFoundryDoc();
+
+ // Inherited from INotifyUI
+ virtual void NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Sets/Gets the file name
+ const char *GetBSPFileName();
+ const char *GetVMFFileName();
+ void SetVMFFileName( const char *pFileName );
+
+ // Dirty bits (has it changed since the last time it was saved?)
+ void SetDirty( bool bDirty );
+ bool IsDirty() const;
+
+ // Saves/loads from file
+ bool LoadFromFile( const char *pFileName );
+ void SaveToFile( );
+
+ // Returns the root object
+ CDmElement *GetRootObject();
+
+ // Called when data changes (see INotifyUI for flags)
+ void OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Create a text block the engine can parse containing the entity data to spawn
+ const char* GenerateEntityData( const char *pActualEntityData );
+
+ // Returns the entity list
+ CDmAttribute *GetEntityList();
+
+ // Deletes an entity
+ void DeleteEntity( CDmeVMFEntity *pEntity );
+
+private:
+ // Always copy the worldspawn and other entities that had data built into them by VBSP out
+ void AddOriginalEntities( CUtlBuffer &entityBuf, const char *pActualEntityData );
+
+ // Copy in other entities from the editable VMF
+ void AddVMFEntities( CUtlBuffer &entityBuf, const char *pActualEntityData );
+
+ IFoundryDocCallback *m_pCallback;
+ CDmeHandle< CDmElement > m_hRoot;
+ char m_pBSPFileName[512];
+ char m_pVMFFileName[512];
+ bool m_bDirty;
+};
+
+
+#endif // FOUNDRYDOC_H
diff --git a/tools/foundry/foundrytool.cpp b/tools/foundry/foundrytool.cpp
new file mode 100644
index 0000000..9f3338e
--- /dev/null
+++ b/tools/foundry/foundrytool.cpp
@@ -0,0 +1,1172 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core Movie Maker UI API
+//
+//=============================================================================
+
+#include "foundrytool.h"
+#include "toolutils/basetoolsystem.h"
+#include "toolutils/recentfilelist.h"
+#include "toolutils/toolmenubar.h"
+#include "toolutils/toolswitchmenubutton.h"
+#include "toolutils/tooleditmenubutton.h"
+#include "toolutils/toolfilemenubutton.h"
+#include "toolutils/toolmenubutton.h"
+#include "vgui_controls/Menu.h"
+#include "tier1/KeyValues.h"
+#include "toolutils/enginetools_int.h"
+#include "toolframework/ienginetool.h"
+#include "vgui/IInput.h"
+#include "vgui/KeyCode.h"
+#include "vgui_controls/FileOpenDialog.h"
+#include "filesystem.h"
+#include "vgui/ilocalize.h"
+#include "dme_controls/elementpropertiestree.h"
+#include "tier0/icommandline.h"
+#include "materialsystem/imaterialsystem.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "toolutils/savewindowpositions.h"
+#include "foundrydoc.h"
+#include "toolutils/toolwindowfactory.h"
+#include "toolutils/basepropertiescontainer.h"
+#include "entityreportpanel.h"
+#include "datamodel/dmelement.h"
+#include "movieobjects/dmeeditortypedictionary.h"
+#include "dmevmfentity.h"
+#include "tier3/tier3.h"
+#include "tier2/fileutils.h"
+#include "vgui/ivgui.h"
+
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Singleton interfaces
+//-----------------------------------------------------------------------------
+CDmeEditorTypeDictionary *g_pEditorTypeDict;
+
+
+const char *GetVGuiControlsModuleName()
+{
+ return "FoundryTool";
+}
+
+//-----------------------------------------------------------------------------
+// Connect, disconnect
+//-----------------------------------------------------------------------------
+bool ConnectTools( CreateInterfaceFn factory )
+{
+ return (materials != NULL) && (g_pMatSystemSurface != NULL);
+}
+
+void DisconnectTools( )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Implementation of the Foundry tool
+//-----------------------------------------------------------------------------
+class CFoundryTool : public CBaseToolSystem, public IFileMenuCallbacks, public IFoundryDocCallback, public IFoundryTool
+{
+ DECLARE_CLASS_SIMPLE( CFoundryTool, CBaseToolSystem );
+
+public:
+ CFoundryTool();
+
+ // Inherited from IToolSystem
+ virtual const char *GetToolName() { return "Foundry"; }
+ virtual const char *GetBindingsContextFile() { return "cfg/Foundry.kb"; }
+ virtual bool Init( );
+ virtual void Shutdown();
+ virtual bool CanQuit();
+ virtual void OnToolActivate();
+ virtual void OnToolDeactivate();
+ virtual const char* GetEntityData( const char *pActualEntityData );
+ virtual void ClientLevelInitPostEntity();
+ virtual void ClientLevelShutdownPreEntity();
+
+ // Inherited from IFileMenuCallbacks
+ virtual int GetFileMenuItemsEnabled( );
+ virtual void AddRecentFilesToMenu( vgui::Menu *menu );
+ virtual bool GetPerforceFileName( char *pFileName, int nMaxLen );
+
+ // Inherited from IFoundryDocCallback
+ virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+ virtual vgui::Panel *GetRootPanel() { return this; }
+ virtual void ShowEntityInEntityProperties( CDmeVMFEntity *pEntity );
+
+ // Inherited from CBaseToolSystem
+ virtual vgui::HScheme GetToolScheme();
+ virtual vgui::Menu *CreateActionMenu( vgui::Panel *pParent );
+ virtual void OnCommand( const char *cmd );
+ virtual const char *GetRegistryName() { return "FoundryTool"; }
+ virtual vgui::MenuBar *CreateMenuBar( CBaseToolSystem *pParent );
+
+public:
+ MESSAGE_FUNC( OnNew, "OnNew" );
+ MESSAGE_FUNC( OnOpen, "OnOpen" );
+ MESSAGE_FUNC( OnSave, "OnSave" );
+ MESSAGE_FUNC( OnSaveAs, "OnSaveAs" );
+ MESSAGE_FUNC( OnClose, "OnClose" );
+ MESSAGE_FUNC( OnCloseNoSave, "OnCloseNoSave" );
+ MESSAGE_FUNC( OnMarkNotDirty, "OnMarkNotDirty" );
+ MESSAGE_FUNC( OnExit, "OnExit" );
+
+ // Commands related to the edit menu
+ KEYBINDING_FUNC( undo, KEY_Z, vgui::MODIFIER_CONTROL, OnUndo, "#undo_help", 0 );
+ KEYBINDING_FUNC( redo, KEY_Z, vgui::MODIFIER_CONTROL | vgui::MODIFIER_SHIFT, OnRedo, "#redo_help", 0 );
+ void OnDescribeUndo();
+
+ // Methods related to the Foundry menu
+ MESSAGE_FUNC( OnReload, "ReloadMap" );
+ MESSAGE_FUNC( OnReloadFromSave, "ReloadFromSave" );
+
+ // Methods related to the view menu
+ MESSAGE_FUNC( OnToggleProperties, "OnToggleProperties" );
+ MESSAGE_FUNC( OnToggleEntityReport, "OnToggleEntityReport" );
+ MESSAGE_FUNC( OnDefaultLayout, "OnDefaultLayout" );
+
+ void PerformNew();
+ void OpenFileFromHistory( int slot );
+ void OpenSpecificFile( const char *pFileName );
+ virtual void SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual void OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues );
+
+ // returns the document
+ CFoundryDoc *GetDocument();
+
+ // Gets at tool windows
+ CBasePropertiesContainer *GetProperties();
+ CEntityReportPanel *GetEntityReport();
+
+private:
+ // Loads up a new document
+ bool LoadDocument( const char *pDocName );
+
+ // Updates the menu bar based on the current file
+ void UpdateMenuBar( );
+
+ // Shows element properties
+ void ShowElementProperties( );
+
+ virtual const char *GetLogoTextureName();
+
+ // Creates, destroys tools
+ void CreateTools( CFoundryDoc *doc );
+ void DestroyTools();
+
+ // Initializes the tools
+ void InitTools();
+
+ // Shows, toggles tool windows
+ void ToggleToolWindow( Panel *tool, char const *toolName );
+ void ShowToolWindow( Panel *tool, char const *toolName, bool visible );
+
+ // Kills all tool windows
+ void DestroyToolContainers();
+
+ // Create custom editors
+ void InitEditorDict();
+
+ // Used to hook DME VMF entities into the render lists
+ void DrawVMFEntitiesInEngine( bool bDrawInEngine );
+
+private:
+ // Document
+ CFoundryDoc *m_pDoc;
+
+ // The menu bar
+ CToolFileMenuBar *m_pMenuBar;
+
+ // Element properties for editing material
+ vgui::DHANDLE< CBasePropertiesContainer > m_hProperties;
+
+ // The entity report
+ vgui::DHANDLE< CEntityReportPanel > m_hEntityReport;
+
+ // The currently viewed entity
+ CDmeHandle< CDmeVMFEntity > m_hCurrentEntity;
+
+ // Separate undo context for the act busy tool
+ CToolWindowFactory< ToolWindow > m_ToolWindowFactory;
+
+ CUtlVector< DmElementHandle_t > m_toolElements;
+};
+
+
+//-----------------------------------------------------------------------------
+// Singleton
+//-----------------------------------------------------------------------------
+CFoundryTool *g_pFoundryToolImp = NULL;
+IFoundryTool *g_pFoundryTool = NULL;
+
+void CreateTools()
+{
+ g_pFoundryTool = g_pFoundryToolImp = new CFoundryTool();
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CFoundryTool::CFoundryTool()
+{
+ m_pMenuBar = NULL;
+ m_pDoc = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Init, shutdown
+//-----------------------------------------------------------------------------
+bool CFoundryTool::Init( )
+{
+ m_pDoc = NULL;
+ m_RecentFiles.LoadFromRegistry( GetRegistryName() );
+
+ // NOTE: This has to happen before BaseClass::Init
+ g_pVGuiLocalize->AddFile( "resource/toolfoundry_%language%.txt" );
+
+ if ( !BaseClass::Init( ) )
+ return false;
+
+ InitEditorDict();
+
+ return true;
+}
+
+void CFoundryTool::Shutdown()
+{
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+
+ {
+ CDisableUndoScopeGuard guard;
+ int nElements = m_toolElements.Count();
+ for ( int i = 0; i < nElements; ++i )
+ {
+ g_pDataModel->DestroyElement( m_toolElements[ i ] );
+ }
+ }
+
+ BaseClass::Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// Create custom editors
+//-----------------------------------------------------------------------------
+void CFoundryTool::InitEditorDict()
+{
+ CDmeEditorAttributeInfo *pInfo;
+
+ // FIXME: This eventually will move to an .fgd-like file.
+ g_pEditorTypeDict = CreateElement<CDmeEditorTypeDictionary>( "DmeEditorTypeDictionary", DMFILEID_INVALID );
+ m_toolElements.AddToTail( g_pEditorTypeDict->GetHandle() );
+
+ CDmeEditorType *pEditorType = CreateElement<CDmeEditorType>( "vmfEntity", DMFILEID_INVALID );
+ m_toolElements.AddToTail( pEditorType->GetHandle() );
+
+ pInfo = CreateElement<CDmeEditorAttributeInfo>( "name info", DMFILEID_INVALID );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "name", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+
+ pInfo = CreateElement<CDmeEditorAttributeInfo>( "type info", DMFILEID_INVALID );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "type", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+
+ pInfo = CreateElement<CDmeEditorAttributeInfo>( "id info", DMFILEID_INVALID );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "id", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+
+ pInfo = CreateElement<CDmeEditorAttributeInfo>( "editor type info", DMFILEID_INVALID );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "editorType", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+
+ pInfo = CreateElement<CDmeEditorAttributeInfo>( "editor info", DMFILEID_INVALID );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "editor", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+
+ pInfo = CreateElement<CDmeEditorAttributeInfo>( "other info", DMFILEID_INVALID );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "other", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+
+ pInfo = CreateElement<CDmeEditorAttributeInfo>( "_visible info", DMFILEID_INVALID );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "_visible", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+
+ pInfo = CreateElement<CDmeEditorAttributeInfo>( "_placeholder info", DMFILEID_INVALID );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "_placeholder", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+
+ g_pEditorTypeDict->AddEditorType( pEditorType );
+}
+
+
+//-----------------------------------------------------------------------------
+// returns the document
+//-----------------------------------------------------------------------------
+inline CFoundryDoc *CFoundryTool::GetDocument()
+{
+ return m_pDoc;
+}
+
+
+//-----------------------------------------------------------------------------
+// Tool activation/deactivation
+//-----------------------------------------------------------------------------
+void CFoundryTool::OnToolActivate()
+{
+ BaseClass::OnToolActivate();
+}
+
+void CFoundryTool::OnToolDeactivate()
+{
+ BaseClass::OnToolDeactivate();
+}
+
+
+//-----------------------------------------------------------------------------
+// Used to hook DME VMF entities into the render lists
+//-----------------------------------------------------------------------------
+void CFoundryTool::DrawVMFEntitiesInEngine( bool bDrawInEngine )
+{
+ if ( !m_pDoc )
+ return;
+
+ const CDmrElementArray<> entities( m_pDoc->GetEntityList() );
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeVMFEntity* pEntity = CastElement<CDmeVMFEntity>( entities[i] );
+ Assert( pEntity );
+ pEntity->DrawInEngine( bDrawInEngine );
+ pEntity->AttachToEngineEntity( bDrawInEngine );
+ }
+}
+
+void CFoundryTool::ClientLevelInitPostEntity()
+{
+ BaseClass::ClientLevelInitPostEntity();
+ DrawVMFEntitiesInEngine( true );
+}
+
+void CFoundryTool::ClientLevelShutdownPreEntity()
+{
+ DrawVMFEntitiesInEngine( false );
+ BaseClass::ClientLevelShutdownPreEntity();
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get a new scheme to be applied to this tool
+//-----------------------------------------------------------------------------
+vgui::HScheme CFoundryTool::GetToolScheme()
+{
+ return vgui::scheme()->LoadSchemeFromFile( "Resource/BoxRocket.res", "BoxRocket" );
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// The View menu
+//
+//-----------------------------------------------------------------------------
+class CFoundryViewMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CFoundryViewMenuButton, CToolMenuButton );
+public:
+ CFoundryViewMenuButton( CFoundryTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+
+private:
+ CFoundryTool *m_pTool;
+};
+
+CFoundryViewMenuButton::CFoundryViewMenuButton( CFoundryTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ m_pTool = parent;
+
+ AddCheckableMenuItem( "properties", "#FoundryProperties", new KeyValues( "OnToggleProperties" ), pActionSignalTarget );
+ AddCheckableMenuItem( "entityreport", "#FoundryEntityReport", new KeyValues( "OnToggleEntityReport" ), pActionSignalTarget );
+
+ AddSeparator();
+
+ AddMenuItem( "defaultlayout", "#FoundryViewDefault", new KeyValues( "OnDefaultLayout" ), pActionSignalTarget );
+
+ SetMenu(m_pMenu);
+}
+
+void CFoundryViewMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ int id;
+
+ CFoundryDoc *pDoc = m_pTool->GetDocument();
+ if ( pDoc )
+ {
+ id = m_Items.Find( "properties" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ Panel *p;
+ p = m_pTool->GetProperties();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+
+ id = m_Items.Find( "entityreport" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ p = m_pTool->GetEntityReport();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+ }
+ else
+ {
+ id = m_Items.Find( "properties" );
+ m_pMenu->SetItemEnabled( id, false );
+ id = m_Items.Find( "entityreport" );
+ m_pMenu->SetItemEnabled( id, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// The Tool menu
+//
+//-----------------------------------------------------------------------------
+class CFoundryToolMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CFoundryToolMenuButton, CToolMenuButton );
+public:
+ CFoundryToolMenuButton( CFoundryTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+
+private:
+ CFoundryTool *m_pTool;
+};
+
+CFoundryToolMenuButton::CFoundryToolMenuButton( CFoundryTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ m_pTool = parent;
+
+ AddMenuItem( "reload", "#FoundryReload", new KeyValues( "ReloadMap" ), pActionSignalTarget );
+ AddMenuItem( "reloadsave", "#FoundryReloadFromSave", new KeyValues( "ReloadFromSave" ), pActionSignalTarget );
+
+ SetMenu(m_pMenu);
+}
+
+void CFoundryToolMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ int id;
+
+ CFoundryDoc *pDoc = m_pTool->GetDocument();
+ id = m_Items.Find( "reload" );
+ m_pMenu->SetItemEnabled( id, pDoc != NULL );
+ id = m_Items.Find( "reloadsave" );
+ m_pMenu->SetItemEnabled( id, pDoc != NULL );
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the menu bar
+//-----------------------------------------------------------------------------
+vgui::MenuBar *CFoundryTool::CreateMenuBar( CBaseToolSystem *pParent )
+{
+ m_pMenuBar = new CToolFileMenuBar( pParent, "Main Menu Bar" );
+
+ // Sets info in the menu bar
+ char title[ 64 ];
+ ComputeMenuBarTitle( title, sizeof( title ) );
+ m_pMenuBar->SetInfo( title );
+ m_pMenuBar->SetToolName( GetToolName() );
+
+ // Add menu buttons
+ CToolMenuButton *pFileButton = CreateToolFileMenuButton( m_pMenuBar, "File", "&File", GetActionTarget(), this );
+ CToolMenuButton *pEditButton = CreateToolEditMenuButton( this, "Edit", "&Edit", GetActionTarget() );
+ CFoundryToolMenuButton *pToolButton = new CFoundryToolMenuButton( this, "Foundry", "F&oundry", GetActionTarget() );
+ CFoundryViewMenuButton *pViewButton = new CFoundryViewMenuButton( this, "View", "&View", GetActionTarget() );
+ CToolMenuButton *pSwitchButton = CreateToolSwitchMenuButton( m_pMenuBar, "Switcher", "&Tools", GetActionTarget() );
+
+ m_pMenuBar->AddButton( pFileButton );
+ m_pMenuBar->AddButton( pEditButton );
+ m_pMenuBar->AddButton( pToolButton );
+ m_pMenuBar->AddButton( pViewButton );
+ m_pMenuBar->AddButton( pSwitchButton );
+
+ return m_pMenuBar;
+}
+
+
+//-----------------------------------------------------------------------------
+// Updates the menu bar based on the current file
+//-----------------------------------------------------------------------------
+void CFoundryTool::UpdateMenuBar( )
+{
+ if ( !m_pDoc )
+ {
+ m_pMenuBar->SetFileName( "#FoundryNoFile" );
+ return;
+ }
+
+ const char *pVMFFile = m_pDoc->GetVMFFileName();
+ if ( !pVMFFile[0] )
+ {
+ m_pMenuBar->SetFileName( "#FoundryNoFile" );
+ return;
+ }
+
+ if ( m_pDoc->IsDirty() )
+ {
+ char sz[ 512 ];
+ Q_snprintf( sz, sizeof( sz ), "* %s", pVMFFile );
+ m_pMenuBar->SetFileName( sz );
+ }
+ else
+ {
+ m_pMenuBar->SetFileName( pVMFFile );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets at tool windows
+//-----------------------------------------------------------------------------
+CBasePropertiesContainer *CFoundryTool::GetProperties()
+{
+ return m_hProperties.Get();
+}
+
+CEntityReportPanel *CFoundryTool::GetEntityReport()
+{
+ return m_hEntityReport.Get();
+}
+
+
+//-----------------------------------------------------------------------------
+// Shows element properties
+//-----------------------------------------------------------------------------
+void CFoundryTool::ShowElementProperties( )
+{
+ if ( !m_pDoc )
+ return;
+
+ // It should already exist
+ Assert( m_hProperties.Get() );
+ if ( m_hProperties.Get() )
+ {
+ m_hProperties->SetObject( m_hCurrentEntity );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Destroys all tool windows
+//-----------------------------------------------------------------------------
+void CFoundryTool::ShowEntityInEntityProperties( CDmeVMFEntity *pEntity )
+{
+ Assert( m_hProperties.Get() );
+ m_hCurrentEntity = pEntity;
+ m_hProperties->SetObject( m_hCurrentEntity );
+}
+
+
+//-----------------------------------------------------------------------------
+// Destroys all tool windows
+//-----------------------------------------------------------------------------
+void CFoundryTool::DestroyToolContainers()
+{
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets up the default layout
+//-----------------------------------------------------------------------------
+void CFoundryTool::OnDefaultLayout()
+{
+ int y = m_pMenuBar->GetTall();
+
+ int usew, useh;
+ GetSize( usew, useh );
+
+ DestroyToolContainers();
+
+ Assert( ToolWindow::GetToolWindowCount() == 0 );
+
+ CBasePropertiesContainer *properties = GetProperties();
+ CEntityReportPanel *pEntityReport = GetEntityReport();
+
+ // Need three containers
+ ToolWindow *pPropertyWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, properties, "#FoundryProperties", false );
+ ToolWindow *pEntityReportWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, pEntityReport, "#FoundryEntityReport", false );
+
+ int halfScreen = usew / 2;
+ int bottom = useh - y;
+ int sy = (bottom - y) / 2;
+ SetMiniViewportBounds( halfScreen, y, halfScreen, sy - y );
+ pEntityReportWindow->SetBounds( 0, y, halfScreen, bottom );
+ pPropertyWindow->SetBounds( halfScreen, sy, halfScreen, bottom - sy );
+}
+
+void CFoundryTool::OnToggleProperties()
+{
+ if ( m_hProperties.Get() )
+ {
+ ToggleToolWindow( m_hProperties.Get(), "#FoundryProperties" );
+ }
+}
+
+void CFoundryTool::OnToggleEntityReport()
+{
+ if ( m_hEntityReport.Get() )
+ {
+ ToggleToolWindow( m_hEntityReport.Get(), "#FoundryEntityReport" );
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Creates
+//-----------------------------------------------------------------------------
+void CFoundryTool::CreateTools( CFoundryDoc *doc )
+{
+ if ( !m_hProperties.Get() )
+ {
+ m_hProperties = new CBasePropertiesContainer( NULL, m_pDoc, g_pEditorTypeDict );
+ }
+
+ if ( !m_hEntityReport.Get() )
+ {
+ m_hEntityReport = new CEntityReportPanel( m_pDoc, this, "EntityReportPanel" );
+ }
+
+ RegisterToolWindow( m_hProperties );
+ RegisterToolWindow( m_hEntityReport );
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the tools
+//-----------------------------------------------------------------------------
+void CFoundryTool::InitTools()
+{
+ ShowElementProperties();
+
+ // FIXME: There are no tool windows here; how should this work?
+ // These panels are saved
+ windowposmgr->RegisterPanel( "properties", m_hProperties, false );
+ windowposmgr->RegisterPanel( "entityreport", m_hEntityReport, false );
+
+ if ( !windowposmgr->LoadPositions( "cfg/foundry.txt", this, &m_ToolWindowFactory, "Foundry" ) )
+ {
+ OnDefaultLayout();
+ }
+}
+
+
+void CFoundryTool::DestroyTools()
+{
+ m_hCurrentEntity = NULL;
+
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+
+ UnregisterAllToolWindows();
+
+ if ( m_hProperties.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hProperties.Get() );
+ delete m_hProperties.Get();
+ m_hProperties = NULL;
+ }
+
+ if ( m_hEntityReport.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hEntityReport.Get() );
+ delete m_hEntityReport.Get();
+ m_hEntityReport = NULL;
+ }
+}
+
+
+void CFoundryTool::ShowToolWindow( Panel *tool, char const *toolName, bool visible )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL && visible )
+ {
+ m_ToolWindowFactory.InstanceToolWindow( this, false, tool, toolName, false );
+ }
+ else if ( !visible )
+ {
+ ToolWindow *tw = dynamic_cast< ToolWindow * >( tool->GetParent()->GetParent() );
+ Assert( tw );
+ tw->RemovePage( tool );
+ }
+}
+
+void CFoundryTool::ToggleToolWindow( Panel *tool, char const *toolName )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL )
+ {
+ ShowToolWindow( tool, toolName, true );
+ }
+ else
+ {
+ ShowToolWindow( tool, toolName, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates the action menu
+//-----------------------------------------------------------------------------
+vgui::Menu *CFoundryTool::CreateActionMenu( vgui::Panel *pParent )
+{
+ vgui::Menu *pActionMenu = new Menu( pParent, "ActionMenu" );
+ pActionMenu->AddMenuItem( "#ToolHide", new KeyValues( "Command", "command", "HideActionMenu" ), GetActionTarget() );
+ return pActionMenu;
+}
+
+//-----------------------------------------------------------------------------
+// Inherited from IFileMenuCallbacks
+//-----------------------------------------------------------------------------
+int CFoundryTool::GetFileMenuItemsEnabled( )
+{
+ int nFlags = FILE_ALL & (~FILE_NEW);
+ if ( m_RecentFiles.IsEmpty() )
+ {
+ nFlags &= ~(FILE_RECENT | FILE_CLEAR_RECENT);
+ }
+ return nFlags;
+}
+
+void CFoundryTool::AddRecentFilesToMenu( vgui::Menu *pMenu )
+{
+ m_RecentFiles.AddToMenu( pMenu, GetActionTarget(), "OnRecent" );
+}
+
+bool CFoundryTool::GetPerforceFileName( char *pFileName, int nMaxLen )
+{
+ if ( !m_pDoc )
+ return false;
+
+ Q_strncpy( pFileName, m_pDoc->GetVMFFileName(), nMaxLen );
+ return pFileName[0] != 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+void CFoundryTool::OnExit()
+{
+ windowposmgr->SavePositions( "cfg/foundry.txt", "Foundry" );
+
+ enginetools->Command( "quit\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Handle commands from the action menu and other menus
+//-----------------------------------------------------------------------------
+void CFoundryTool::OnCommand( const char *cmd )
+{
+ if ( !V_stricmp( cmd, "HideActionMenu" ) )
+ {
+ if ( GetActionMenu() )
+ {
+ GetActionMenu()->SetVisible( false );
+ }
+ }
+ else if ( const char *pSuffix = StringAfterPrefix( cmd, "OnRecent" ) )
+ {
+ int idx = Q_atoi( pSuffix );
+ OpenFileFromHistory( idx );
+ }
+ else if ( const char *pSuffixTool = StringAfterPrefix( cmd, "OnTool" ) )
+ {
+ int idx = Q_atoi( pSuffixTool );
+ enginetools->SwitchToTool( idx );
+ }
+ else if ( !V_stricmp( cmd, "OnUndo" ) )
+ {
+ OnUndo();
+ }
+ else if ( !V_stricmp( cmd, "OnRedo" ) )
+ {
+ OnRedo();
+ }
+ else if ( !V_stricmp( cmd, "OnDescribeUndo" ) )
+ {
+ OnDescribeUndo();
+ }
+ else
+ {
+ BaseClass::OnCommand( cmd );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Command handlers
+//-----------------------------------------------------------------------------
+void CFoundryTool::PerformNew()
+{
+ // Can never do new
+ Assert( 0 );
+}
+
+void CFoundryTool::OnNew()
+{
+ if ( m_pDoc )
+ {
+ if ( m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetVMFFileName(), "vmf", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnNew" ) );
+ return;
+ }
+ }
+ PerformNew();
+}
+
+void CFoundryTool::OnOpen( )
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetVMFFileName();
+ }
+
+ OpenFile( "bsp", pSaveFileName, "vmf", nFlags );
+}
+
+bool CFoundryTool::OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ OnCloseNoSave();
+ if ( !LoadDocument( pFileName ) )
+ return false;
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ UpdateMenuBar();
+ return true;
+}
+
+void CFoundryTool::OnSave()
+{
+ if ( m_pDoc )
+ {
+ SaveFile( NULL, "vmf", FOSM_SHOW_PERFORCE_DIALOGS );
+ }
+}
+
+void CFoundryTool::OnSaveAs()
+{
+ if ( m_pDoc )
+ {
+ SaveFile( m_pDoc->GetVMFFileName(), "vmf", FOSM_SHOW_PERFORCE_DIALOGS );
+ }
+}
+
+bool CFoundryTool::OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ if ( !m_pDoc )
+ return true;
+
+ m_pDoc->SetVMFFileName( pFileName );
+ m_pDoc->SaveToFile( );
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ UpdateMenuBar();
+ return true;
+}
+
+void CFoundryTool::OnClose()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetVMFFileName(), "vmf", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnClose" ) );
+ return;
+ }
+
+ OnCloseNoSave();
+}
+
+void CFoundryTool::OnCloseNoSave()
+{
+ // FIXME: Implement
+}
+
+void CFoundryTool::OnMarkNotDirty()
+{
+ // FIXME: Implement
+}
+
+
+//-----------------------------------------------------------------------------
+// Open a specific file
+//-----------------------------------------------------------------------------
+void CFoundryTool::OpenSpecificFile( const char *pFileName )
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc )
+ {
+ // File is already open
+ if ( !Q_stricmp( m_pDoc->GetVMFFileName(), pFileName ) )
+ return;
+
+ if ( m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetVMFFileName();
+ }
+ else
+ {
+ OnCloseNoSave();
+ }
+ }
+
+ OpenFile( pFileName, "bsp", pSaveFileName, "vmf", nFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the save document query dialog
+//-----------------------------------------------------------------------------
+void CFoundryTool::OpenFileFromHistory( int slot )
+{
+ const char *pFileName = m_RecentFiles.GetFile( slot );
+ if ( !pFileName )
+ return;
+ OpenSpecificFile( pFileName );
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get notified when files are saved/loaded
+//-----------------------------------------------------------------------------
+void CFoundryTool::OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues )
+{
+ if ( bWroteFile )
+ {
+ OnMarkNotDirty();
+ }
+
+ if ( !pContextKeyValues )
+ return;
+
+ if ( state != FileOpenStateMachine::SUCCESSFUL )
+ return;
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnNew" ) )
+ {
+ PerformNew();
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnClose" ) )
+ {
+ OnCloseNoSave();
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnQuit" ) )
+ {
+ OnCloseNoSave();
+ vgui::ivgui()->PostMessage( GetVPanel(), new KeyValues( "OnExit" ), 0 );
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the File browser dialog
+//-----------------------------------------------------------------------------
+void CFoundryTool::SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ char pStartingDir[ MAX_PATH ];
+
+ // We open BSPs, but save-as VMFs
+ if ( bOpenFile )
+ {
+ GetModSubdirectory( "maps", pStartingDir, sizeof(pStartingDir) );
+ pDialog->SetTitle( "Choose Valve BSP File", true );
+ pDialog->SetStartDirectoryContext( "foundry_bsp_session", pStartingDir );
+ pDialog->AddFilter( "*.bsp", "Valve BSP File (*.bsp)", true );
+ }
+ else
+ {
+ GetModContentSubdirectory( "maps", pStartingDir, sizeof(pStartingDir) );
+ pDialog->SetTitle( "Choose Valve VMF File", true );
+ pDialog->SetStartDirectoryContext( "foundry_vmf_session", pStartingDir );
+ pDialog->AddFilter( "*.vmf", "Valve VMF File (*.vmf)", true );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Can we quit?
+//-----------------------------------------------------------------------------
+bool CFoundryTool::CanQuit()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ // Show Save changes Yes/No/Cancel and re-quit if hit yes/no
+ SaveFile( m_pDoc->GetVMFFileName(), "vmf", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnQuit" ) );
+ return false;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Various command handlers related to the Edit menu
+//-----------------------------------------------------------------------------
+void CFoundryTool::OnUndo()
+{
+ CDisableUndoScopeGuard guard;
+ g_pDataModel->Undo();
+}
+
+void CFoundryTool::OnRedo()
+{
+ CDisableUndoScopeGuard guard;
+ g_pDataModel->Redo();
+}
+
+void CFoundryTool::OnDescribeUndo()
+{
+ CUtlVector< UndoInfo_t > list;
+ g_pDataModel->GetUndoInfo( list );
+
+ Msg( "%i operations in stack\n", list.Count() );
+
+ for ( int i = list.Count() - 1; i >= 0; --i )
+ {
+ UndoInfo_t& entry = list[ i ];
+ if ( entry.terminator )
+ {
+ Msg( "[ '%s' ] - %i operations\n", entry.undo, entry.numoperations );
+ }
+
+ Msg( " +%s\n", entry.desc );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Foundry menu items
+//-----------------------------------------------------------------------------
+void CFoundryTool::OnReload()
+{
+ // Reloads the map, entities only, will reload every entity
+ enginetools->Command( "respawn_entities\n" );
+}
+
+void CFoundryTool::OnReloadFromSave()
+{
+ // Reloads the map from a save point, overrides selected entities
+ // for now, this is hardcoded to be info_targets
+ enginetools->Command( "load quick\n" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Background
+//-----------------------------------------------------------------------------
+const char *CFoundryTool::GetLogoTextureName()
+{
+ return "vgui/tools/sampletool/sampletool_logo";
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from IFoundryDocCallback
+//-----------------------------------------------------------------------------
+void CFoundryTool::OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ UpdateMenuBar();
+
+ /*
+ if ( bRefreshUI && m_hProperties.Get() )
+ {
+ m_hProperties->Refresh();
+ }
+ */
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads up a new document
+//-----------------------------------------------------------------------------
+bool CFoundryTool::LoadDocument( const char *pDocName )
+{
+ Assert( !m_pDoc );
+
+ DestroyTools();
+
+ m_pDoc = new CFoundryDoc( this );
+ if ( !m_pDoc->LoadFromFile( pDocName ) )
+ {
+ delete m_pDoc;
+ m_pDoc = NULL;
+ Warning( "Fatal error loading '%s'\n", pDocName );
+ return false;
+ }
+
+ ShowMiniViewport( true );
+
+ CreateTools( m_pDoc );
+ InitTools();
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Create the entities that are in our VMF file
+//-----------------------------------------------------------------------------
+const char* CFoundryTool::GetEntityData( const char *pActualEntityData )
+{
+ if ( !m_pDoc )
+ return pActualEntityData;
+
+ return m_pDoc->GenerateEntityData( pActualEntityData );
+}
diff --git a/tools/foundry/foundrytool.h b/tools/foundry/foundrytool.h
new file mode 100644
index 0000000..c2e81f7
--- /dev/null
+++ b/tools/foundry/foundrytool.h
@@ -0,0 +1,65 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Foundry tool; main UI smarts class
+//
+//=============================================================================
+
+#ifndef FOUNDRYTOOL_H
+#define FOUNDRYTOOL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/platform.h"
+#include "datamodel/idatamodel.h"
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CDmeEditorTypeDictionary;
+class CDmeVMFEntity;
+
+namespace vgui
+{
+ class Panel;
+}
+
+
+//-----------------------------------------------------------------------------
+// Singleton interfaces
+//-----------------------------------------------------------------------------
+extern CDmeEditorTypeDictionary *g_pEditorTypeDict;
+
+
+//-----------------------------------------------------------------------------
+// Allows the doc to call back into the Foundry editor tool
+//-----------------------------------------------------------------------------
+abstract_class IFoundryDocCallback
+{
+public:
+ // Called by the doc when the data changes
+ virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags ) = 0;
+};
+
+
+//-----------------------------------------------------------------------------
+// Global methods of the foundry tool
+//-----------------------------------------------------------------------------
+abstract_class IFoundryTool
+{
+public:
+ // Gets at the rool panel (for modal dialogs)
+ virtual vgui::Panel *GetRootPanel() = 0;
+
+ // Gets the registry name (for saving settings)
+ virtual const char *GetRegistryName() = 0;
+
+ // Shows a particular entity in the entity properties dialog
+ virtual void ShowEntityInEntityProperties( CDmeVMFEntity *pEntity ) = 0;
+};
+
+extern IFoundryTool *g_pFoundryTool;
+
+
+#endif // FOUNDRYTOOL_H
diff --git a/tools/gameevents/gameeventeditdoc.cpp b/tools/gameevents/gameeventeditdoc.cpp
new file mode 100644
index 0000000..909f16e
--- /dev/null
+++ b/tools/gameevents/gameeventeditdoc.cpp
@@ -0,0 +1,182 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "gameeventeditdoc.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "toolutils/enginetools_int.h"
+#include "filesystem.h"
+#include "toolframework/ienginetool.h"
+#include "datamodel/idatamodel.h"
+#include "toolutils/attributeelementchoicelist.h"
+#include "vgui_controls/messagebox.h"
+
+// FIXME: This document currently stores a whole lot of nothing.
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CGameEventEditDoc::CGameEventEditDoc()
+{
+ m_hRoot = NULL;
+ m_pTXTFileName[0] = 0;
+ m_bDirty = false;
+ g_pDataModel->InstallNotificationCallback( this );
+}
+
+CGameEventEditDoc::~CGameEventEditDoc()
+{
+ g_pDataModel->RemoveNotificationCallback( this );
+}
+
+//-----------------------------------------------------------------------------
+// Inherited from INotifyUI
+//-----------------------------------------------------------------------------
+void CGameEventEditDoc::NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ //OnDataChanged( pReason, nNotifySource, nNotifyFlags );
+}
+
+//-----------------------------------------------------------------------------
+// Gets the file name
+//-----------------------------------------------------------------------------
+const char *CGameEventEditDoc::GetTXTFileName()
+{
+ return m_pTXTFileName;
+}
+
+void CGameEventEditDoc::SetTXTFileName( const char *pFileName )
+{
+ Q_strncpy( m_pTXTFileName, pFileName, sizeof( m_pTXTFileName ) );
+ Q_FixSlashes( m_pTXTFileName );
+ SetDirty( true );
+}
+
+//-----------------------------------------------------------------------------
+// Dirty bits
+//-----------------------------------------------------------------------------
+void CGameEventEditDoc::SetDirty( bool bDirty )
+{
+ m_bDirty = bDirty;
+}
+
+bool CGameEventEditDoc::IsDirty() const
+{
+ return m_bDirty;
+}
+
+//-----------------------------------------------------------------------------
+// Saves/loads from file
+//-----------------------------------------------------------------------------
+bool CGameEventEditDoc::LoadFromFile( const char *pFileName )
+{
+/*
+ Assert( !m_hRoot.Get() );
+
+ CAppDisableUndoScopeGuard guard( "CCommEditDoc::LoadFromFile", 0 );
+ SetDirty( false );
+
+ if ( !pFileName[0] )
+ return false;
+
+ char mapname[ 256 ];
+
+ // Compute the map name
+ const char *pMaps = Q_stristr( pFileName, "\\maps\\" );
+ if ( !pMaps )
+ return false;
+
+ // Build map name
+ //int nNameLen = (int)( (size_t)pComm - (size_t)pMaps ) - 5;
+ Q_StripExtension( pFileName, mapname, sizeof(mapname) );
+ char *pszFileName = (char*)Q_UnqualifiedFileName(mapname);
+
+ // Set the txt file name.
+ // If we loaded an existing commentary file, keep the same filename.
+ // If we loaded a .bsp, change the name & the extension.
+ if ( !V_stricmp( Q_GetFileExtension( pFileName ), "bsp" ) )
+ {
+ const char *pCommentaryAppend = "_commentary.txt";
+ Q_StripExtension( pFileName, m_pTXTFileName, sizeof(m_pTXTFileName)- strlen(pCommentaryAppend) - 1 );
+ Q_strcat( m_pTXTFileName, pCommentaryAppend, sizeof( m_pTXTFileName ) );
+
+ if ( g_pFileSystem->FileExists( m_pTXTFileName ) )
+ {
+ char pBuf[1024];
+ Q_snprintf( pBuf, sizeof(pBuf), "File %s already exists!\n", m_pTXTFileName );
+ m_pTXTFileName[0] = 0;
+ vgui::MessageBox *pMessageBox = new vgui::MessageBox( "Unable to overwrite file!\n", pBuf, g_pCommEditTool );
+ pMessageBox->DoModal( );
+ return false;
+ }
+
+ DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( m_pTXTFileName );
+
+ m_hRoot = CreateElement<CDmElement>( "root", fileid );
+ CDmrElementArray<> subkeys( m_hRoot->AddAttribute( "subkeys", AT_ELEMENT_ARRAY ) );
+ CDmElement *pRoot2 = CreateElement<CDmElement>( "Entities", fileid );
+ pRoot2->AddAttribute( "subkeys", AT_ELEMENT_ARRAY );
+ subkeys.AddToTail( pRoot2 );
+ g_pDataModel->SetFileRoot( fileid, m_hRoot );
+ }
+ else
+ {
+ char *pComm = Q_stristr( pszFileName, "_commentary" );
+ if ( !pComm )
+ {
+ char pBuf[1024];
+ Q_snprintf( pBuf, sizeof(pBuf), "File %s is not a commentary file!\nThe file name must end in _commentary.txt.\n", m_pTXTFileName );
+ m_pTXTFileName[0] = 0;
+ vgui::MessageBox *pMessageBox = new vgui::MessageBox( "Bad file name!\n", pBuf, g_pCommEditTool );
+ pMessageBox->DoModal( );
+ return false;
+ }
+
+ // Clip off the "_commentary" at the end of the filename
+ *pComm = '\0';
+
+ // This is not undoable
+ CDisableUndoScopeGuard guard;
+
+ CDmElement *pTXT = NULL;
+
+ CElementForKeyValueCallback KeyValuesCallback;
+ g_pDataModel->SetKeyValuesElementCallback( &KeyValuesCallback );
+ DmFileId_t fileid = g_pDataModel->RestoreFromFile( pFileName, NULL, "keyvalues", &pTXT );
+ g_pDataModel->SetKeyValuesElementCallback( NULL );
+
+ if ( fileid == DMFILEID_INVALID )
+ {
+ m_pTXTFileName[0] = 0;
+ return false;
+ }
+
+ SetTXTFileName( pFileName );
+ m_hRoot = pTXT;
+ }
+
+ guard.Release();
+ SetDirty( false );
+
+ char cmd[ 256 ];
+ Q_snprintf( cmd, sizeof( cmd ), "disconnect; map %s\n", pszFileName );
+ enginetools->Command( cmd );
+ enginetools->Execute( );*/
+
+ return true;
+}
+
+void CGameEventEditDoc::SaveToFile( )
+{
+ if ( m_hRoot.Get() && m_pTXTFileName && m_pTXTFileName[0] )
+ {
+ g_pDataModel->SaveToFile( m_pTXTFileName, NULL, "keyvalues", "keyvalues", m_hRoot );
+ }
+
+ SetDirty( false );
+} \ No newline at end of file
diff --git a/tools/gameevents/gameeventeditdoc.h b/tools/gameevents/gameeventeditdoc.h
new file mode 100644
index 0000000..4b96c8b
--- /dev/null
+++ b/tools/gameevents/gameeventeditdoc.h
@@ -0,0 +1,94 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef GAMEEVENTEDITDOC_H
+#define GAMEEVENTEDITDOC_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "dme_controls/inotifyui.h"
+#include "datamodel/dmehandle.h"
+#include "datamodel/dmelement.h"
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class ICommEditDocCallback;
+class CCommEditDoc;
+class CDmeCommentaryNodeEntity;
+
+typedef CDmrElementArray<CDmeCommentaryNodeEntity> CDmrCommentaryNodeEntityList;
+
+
+//-----------------------------------------------------------------------------
+// Contains all editable state
+//-----------------------------------------------------------------------------
+class CGameEventEditDoc : public IDmNotify
+{
+public:
+ CGameEventEditDoc();
+ ~CGameEventEditDoc();
+
+ // Inherited from INotifyUI
+ virtual void NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Sets/Gets the file name
+ const char *GetTXTFileName();
+ void SetTXTFileName( const char *pFileName );
+
+ // Dirty bits (has it changed since the last time it was saved?)
+ void SetDirty( bool bDirty );
+ bool IsDirty() const;
+
+ // Saves/loads from file
+ bool LoadFromFile( const char *pFileName );
+ void SaveToFile( );
+
+ /*
+ // Returns the root object
+ CDmElement *GetRootObject();
+
+ // Called when data changes (see INotifyUI for flags)
+ void OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Returns the entity list
+ CDmAttribute *GetEntityList();
+
+ // Adds a new info_target
+ void AddNewInfoTarget( void );
+ void AddNewInfoTarget( const Vector &vecOrigin, const QAngle &angAngles );
+
+ // Adds a new commentary node
+ void AddNewCommentaryNode( void );
+ void AddNewCommentaryNode( const Vector &vecOrigin, const QAngle &angAngles );
+
+ // Deletes a commentary node
+ void DeleteCommentaryNode( CDmElement *pNode );
+
+ // Returns the commentary node at the specified location
+ CDmeCommentaryNodeEntity *GetCommentaryNodeForLocation( Vector &vecOrigin, QAngle &angAbsAngles );
+
+ // For element choice lists. Return false if it's an unknown choice list type
+ virtual bool GetStringChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, StringChoiceList_t &list );
+ virtual bool GetElementChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, ElementChoiceList_t &list );*/
+
+
+private:
+ //ICommEditDocCallback *m_pCallback;
+ CDmeHandle< CDmElement > m_hRoot;
+ char m_pTXTFileName[512];
+ bool m_bDirty;
+};
+
+
+#endif // GAMEEVENTEDITDOC_H
diff --git a/tools/gameevents/gameeventeditpanel.cpp b/tools/gameevents/gameeventeditpanel.cpp
new file mode 100644
index 0000000..59f0e33
--- /dev/null
+++ b/tools/gameevents/gameeventeditpanel.cpp
@@ -0,0 +1,240 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+#include "gameeventeditpanel.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "iregistry.h"
+#include "vgui/ivgui.h"
+#include "vgui_controls/listpanel.h"
+#include "vgui_controls/textentry.h"
+#include "vgui_controls/checkbutton.h"
+#include "vgui_controls/combobox.h"
+#include "vgui_controls/radiobutton.h"
+#include "vgui_controls/messagebox.h"
+#include "vgui_controls/scrollbar.h"
+#include "vgui_controls/scrollableeditablepanel.h"
+#include "datamodel/dmelement.h"
+#include "matsys_controls/picker.h"
+#include "vgui_controls/fileopendialog.h"
+#include "filesystem.h"
+#include "tier2/fileutils.h"
+#include "igameevents.h"
+#include "toolutils/enginetools_int.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+char *VarArgs( PRINTF_FORMAT_STRING const char *format, ... )
+{
+ va_list argptr;
+ static char string[1024];
+
+ va_start (argptr, format);
+ Q_vsnprintf (string, sizeof( string ), format,argptr);
+ va_end (argptr);
+
+ return string;
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CGameEventEditPanel::CGameEventEditPanel( CGameEventEditDoc *pDoc, vgui::Panel* pParent )
+: BaseClass( pParent, "GameEventEditPanel" ), m_pDoc( pDoc )
+{
+ SetPaintBackgroundEnabled( true );
+ SetKeyBoardInputEnabled( true );
+
+ m_pEvents = new KeyValues( "events" );
+
+ m_EventFiles.RemoveAll();
+ m_EventFileNames.RemoveAll();
+
+ // load the game events
+ LoadEventsFromFile( "resource/GameEvents.res" );
+ LoadEventsFromFile( "resource/ModEvents.res" );
+
+ m_pEventCombo = new vgui::ComboBox( this, "EventComboBox", 30, false );
+ m_pEventCombo->SetNumberOfEditLines( 30 );
+
+ KeyValues *subkey = m_pEvents->GetFirstSubKey();
+ while ( subkey )
+ {
+ m_pEventCombo->AddItem( subkey->GetName(), subkey );
+ subkey = subkey->GetNextKey();
+ }
+
+ if ( m_pEventCombo->GetItemCount() > 0 )
+ {
+ m_pEventCombo->ActivateItemByRow( 0 );
+ }
+
+ for ( int i=0;i<MAX_GAME_EVENT_PARAMS;i++ )
+ {
+ m_pParamLabels[i] = new vgui::Label( this, VarArgs( "ParamLabel%d", i+1 ), VarArgs( "event param %d:", i+1 ) );
+ m_pParamLabels[i]->AddActionSignalTarget( this );
+
+ m_pParams[i] = new vgui::TextEntry( this, VarArgs( "Param%d", i+1 ) );
+ m_pParams[i]->AddActionSignalTarget( this );
+ }
+
+ m_pSendEventButton = new vgui::Button( this, "SendEvent", "", this, "SendEvent" );
+
+ m_pFilterBox = new vgui::TextEntry( this, "FilterBox" );
+
+ LoadControlSettings( "resource/gameeventeditpanel.res" );
+}
+
+CGameEventEditPanel::~CGameEventEditPanel()
+{
+ m_pEvents->deleteThis();
+}
+
+void CGameEventEditPanel::OnTextChanged( KeyValues *params )
+{
+ Panel *panel = reinterpret_cast<vgui::Panel *>( params->GetPtr("panel") );
+
+ if ( panel == m_pFilterBox )
+ {
+ // repopulate the list based on the filter substr
+ char filter[128];
+ m_pFilterBox->GetText( filter, sizeof(filter) );
+ int len = Q_strlen(filter);
+
+ m_pEventCombo->RemoveAll();
+
+ KeyValues *subkey = m_pEvents->GetFirstSubKey();
+ while ( subkey )
+ {
+ if ( len == 0 || Q_strstr( subkey->GetName(), filter ) )
+ {
+ m_pEventCombo->AddItem( subkey->GetName(), subkey );
+ }
+
+ subkey = subkey->GetNextKey();
+ }
+
+ if ( m_pEventCombo->GetItemCount() > 0 )
+ {
+ m_pEventCombo->ActivateItemByRow( 0 );
+ }
+ }
+
+ if ( panel == m_pEventCombo )
+ {
+ Msg( "%s", params->GetName() );
+
+ KeyValues *kv = m_pEventCombo->GetActiveItemUserData();
+
+ int i = 0;
+
+ if ( kv )
+ {
+ KeyValues *subkey = kv->GetFirstSubKey();
+ while ( subkey && i < MAX_GAME_EVENT_PARAMS )
+ {
+ Msg( subkey->GetName() );
+
+ char buf[128];
+ Q_snprintf( buf, sizeof(buf), "%s (%s)", subkey->GetName(), subkey->GetString() );
+
+ m_pParamLabels[i]->SetText( buf );
+ m_pParamLabels[i]->SetVisible( true );
+
+ const char *type = subkey->GetString();
+
+ if ( !Q_strcmp( type, "string" ) )
+ {
+ m_pParams[i]->SetAllowNumericInputOnly( false );
+ }
+ else
+ {
+ m_pParams[i]->SetAllowNumericInputOnly( true );
+ }
+ m_pParams[i]->SetText( "" );
+ m_pParams[i]->SetVisible( true );
+
+ subkey = subkey->GetNextKey();
+ i++;
+ }
+
+ while( i < MAX_GAME_EVENT_PARAMS )
+ {
+ m_pParamLabels[i]->SetVisible( false );
+ m_pParams[i]->SetVisible( false );
+ i++;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Called when buttons are clicked
+//-----------------------------------------------------------------------------
+void CGameEventEditPanel::OnCommand( const char *pCommand )
+{
+ if ( !Q_stricmp( pCommand, "SendEvent" ) )
+ {
+ KeyValues *pData = m_pEventCombo->GetActiveItemUserData();
+
+ if ( pData )
+ {
+ const char *pEventName = pData->GetName();
+
+ IGameEvent *event = gameeventmanager->CreateEvent( pEventName );
+ if ( event )
+ {
+ KeyValues *subkey = pData->GetFirstSubKey();
+
+ int i = 0;
+
+ while( subkey && i < MAX_GAME_EVENT_PARAMS )
+ {
+ char text[128];
+ m_pParams[i]->GetText( text, sizeof(text) );
+ event->SetString( subkey->GetName(), text );
+
+ subkey = subkey->GetNextKey();
+ i++;
+ }
+
+ gameeventmanager->FireEvent( event );
+ }
+ }
+
+ return;
+ }
+
+ BaseClass::OnCommand( pCommand );
+}
+
+void CGameEventEditPanel::LoadEventsFromFile( const char *filename )
+{
+ if ( UTL_INVAL_SYMBOL == m_EventFiles.Find( filename ) )
+ {
+ CUtlSymbol id = m_EventFiles.AddString( filename );
+ m_EventFileNames.AddToTail( id );
+ }
+
+ KeyValues * key = new KeyValues(filename);
+ KeyValues::AutoDelete autodelete_key( key );
+
+ if ( !key->LoadFromFile( g_pFileSystem, filename, "GAME" ) )
+ return;
+
+ KeyValues *subkey = key->GetFirstSubKey();
+ while ( subkey )
+ {
+ KeyValues *copy = subkey->MakeCopy();
+
+ m_pEvents->AddSubKey( copy );
+
+ subkey = subkey->GetNextKey();
+ }
+} \ No newline at end of file
diff --git a/tools/gameevents/gameeventeditpanel.h b/tools/gameevents/gameeventeditpanel.h
new file mode 100644
index 0000000..ba11733
--- /dev/null
+++ b/tools/gameevents/gameeventeditpanel.h
@@ -0,0 +1,90 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#ifndef GAMEEVENTEDITPANEL_H
+#define GAMEEVENTEDITPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/editablepanel.h"
+#include "tier1/utlstring.h"
+#include "datamodel/dmehandle.h"
+#include "igameevents.h"
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CGameEventEditDoc;
+
+namespace vgui
+{
+ class ComboBox;
+ class Button;
+ class TextEntry;
+ class ListPanel;
+ class CheckButton;
+ class RadioButton;
+}
+
+#define MAX_GAME_EVENT_PARAMS 20
+
+extern IGameEventManager2 *gameeventmanager;
+
+//-----------------------------------------------------------------------------
+// Panel that shows all entities in the level
+//-----------------------------------------------------------------------------
+class CGameEventEditPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CGameEventEditPanel, vgui::EditablePanel );
+
+public:
+ CGameEventEditPanel( CGameEventEditDoc *pDoc, vgui::Panel* pParent ); // standard constructor
+ ~CGameEventEditPanel();
+
+ // Inherited from Panel
+ virtual void OnCommand( const char *pCommand );
+
+private:
+ // Text to attribute...
+ //void TextEntryToAttribute( vgui::TextEntry *pEntry, const char *pAttributeName );
+ //void TextEntriesToVector( vgui::TextEntry *pEntry[3], const char *pAttributeName );
+
+ // Messages handled
+ /*
+ MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", kv );
+ MESSAGE_FUNC_PARAMS( OnSoundSelected, "SoundSelected", kv );
+ MESSAGE_FUNC_PARAMS( OnPicked, "Picked", kv );
+ MESSAGE_FUNC_PARAMS( OnFileSelected, "FileSelected", kv );
+ MESSAGE_FUNC_PARAMS( OnSoundRecorded, "SoundRecorded", kv );*/
+
+ //MESSAGE_FUNC( OnEventSend, "SendEvent" );
+
+ MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", kv );
+
+ void LoadEventsFromFile( const char *filename );
+
+ CGameEventEditDoc *m_pDoc;
+
+ // drop down of available events
+
+ vgui::ComboBox *m_pEventCombo;
+
+ vgui::Label *m_pParamLabels[MAX_GAME_EVENT_PARAMS];
+ vgui::TextEntry *m_pParams[MAX_GAME_EVENT_PARAMS];
+
+ vgui::Button *m_pSendEventButton;
+
+ CUtlSymbolTable m_EventFiles; // list of all loaded event files
+ CUtlVector<CUtlSymbol> m_EventFileNames;
+
+ KeyValues *m_pEvents;
+
+ vgui::TextEntry *m_pFilterBox;
+};
+
+
+#endif // GAMEEVENTEDITPANEL_H
diff --git a/tools/gameevents/gameevents.cpp b/tools/gameevents/gameevents.cpp
new file mode 100644
index 0000000..d2eabb0
--- /dev/null
+++ b/tools/gameevents/gameevents.cpp
@@ -0,0 +1,625 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "toolutils/basetoolsystem.h"
+#include "toolutils/recentfilelist.h"
+#include "toolutils/toolmenubar.h"
+#include "toolutils/toolswitchmenubutton.h"
+#include "toolutils/toolfilemenubutton.h"
+#include "toolutils/toolmenubutton.h"
+#include "vgui_controls/Menu.h"
+#include "tier1/KeyValues.h"
+#include "toolutils/enginetools_int.h"
+#include "toolframework/ienginetool.h"
+#include "vgui/IInput.h"
+#include "vgui/KeyCode.h"
+#include "vgui_controls/FileOpenDialog.h"
+#include "filesystem.h"
+#include "vgui/ilocalize.h"
+#include "dme_controls/elementpropertiestree.h"
+#include "tier0/icommandline.h"
+#include "materialsystem/imaterialsystem.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "tier3/tier3.h"
+#include "tier2/fileutils.h"
+#include "gameeventeditdoc.h"
+#include "gameeventeditpanel.h"
+#include "toolutils/toolwindowfactory.h"
+#include "toolutils/savewindowpositions.h" // for windowposmgr
+#include "toolutils/ConsolePage.h"
+#include "igameevents.h"
+
+IGameEventManager2 *gameeventmanager = NULL;
+
+using namespace vgui;
+
+
+const char *GetVGuiControlsModuleName()
+{
+ return "GameEvents";
+}
+
+//-----------------------------------------------------------------------------
+// Connect, disconnect
+//-----------------------------------------------------------------------------
+bool ConnectTools( CreateInterfaceFn factory )
+{
+ gameeventmanager = ( IGameEventManager2 * )factory( INTERFACEVERSION_GAMEEVENTSMANAGER2, NULL );
+
+ if ( !gameeventmanager )
+ {
+ Warning( "Game Event Tool missing required interface\n" );
+ return false;
+ }
+
+ return (materials != NULL) && (g_pMatSystemSurface != NULL);
+}
+
+void DisconnectTools( )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Implementation of the game events tool
+//-----------------------------------------------------------------------------
+class CGameEventTool : public CBaseToolSystem, public IFileMenuCallbacks
+{
+ DECLARE_CLASS_SIMPLE( CGameEventTool, CBaseToolSystem );
+
+public:
+ CGameEventTool();
+
+ // Inherited from IToolSystem
+ virtual const char *GetToolName() { return "Game Events"; }
+ virtual const char *GetBindingsContextFile() { return "cfg/GameEvents.kb"; }
+ virtual bool Init( );
+ virtual void Shutdown();
+
+ // Inherited from IFileMenuCallbacks
+ virtual int GetFileMenuItemsEnabled( );
+ virtual void AddRecentFilesToMenu( vgui::Menu *menu );
+ virtual bool GetPerforceFileName( char *pFileName, int nMaxLen ) { return false; }
+ virtual vgui::Panel* GetRootPanel() { return this; }
+
+ // Inherited from CBaseToolSystem
+ virtual vgui::HScheme GetToolScheme();
+ virtual vgui::Menu *CreateActionMenu( vgui::Panel *pParent );
+ virtual void OnCommand( const char *cmd );
+ virtual const char *GetRegistryName() { return "SampleTool"; }
+ virtual vgui::MenuBar *CreateMenuBar( CBaseToolSystem *pParent );
+
+public:
+ MESSAGE_FUNC( OnNew, "OnNew" );
+ MESSAGE_FUNC( OnOpen, "OnOpen" );
+ MESSAGE_FUNC( OnSave, "OnSave" );
+ MESSAGE_FUNC( OnSaveAs, "OnSaveAs" );
+ MESSAGE_FUNC( OnClose, "OnClose" );
+ MESSAGE_FUNC( OnCloseNoSave, "OnCloseNoSave" );
+ MESSAGE_FUNC( OnMarkNotDirty, "OnMarkNotDirty" );
+ MESSAGE_FUNC( OnExit, "OnExit" );
+
+ void NewDocument();
+
+ void OpenFileFromHistory( int slot );
+ virtual void SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual void OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues );
+
+ // Get at the edit panel
+ CGameEventEditPanel *GetGameEventEditPanel();
+
+private:
+ // Loads up a new document
+ bool LoadDocument( const char *pDocName );
+
+ // Creates, destroys tools
+ void CreateTools( CGameEventEditDoc *doc );
+ void InitTools();
+ void DestroyTools();
+
+ void OnDefaultLayout();
+
+ // Updates the menu bar based on the current file
+ void UpdateMenuBar( );
+
+ // Shows element properties
+ void ShowElementProperties( );
+
+ virtual const char *GetLogoTextureName();
+
+ CConsolePage *GetConsole();
+ void OnToggleConsole();
+
+ void ShowToolWindow( Panel *tool, char const *toolName, bool visible );
+ void ToggleToolWindow( Panel *tool, char const *toolName );
+
+ CToolWindowFactory< ToolWindow > m_ToolWindowFactory;
+
+
+ // The entity report
+ vgui::DHANDLE< CGameEventEditPanel > m_hGameEventEditPanel;
+
+ // Document
+ CGameEventEditDoc *m_pDoc;
+
+ // The menu bar
+ CToolFileMenuBar *m_pMenuBar;
+
+ // console tab in viewport
+ vgui::DHANDLE< CConsolePage > m_hConsole;
+};
+
+
+//-----------------------------------------------------------------------------
+// Singleton
+//-----------------------------------------------------------------------------
+CGameEventTool *g_pSampleTool = NULL;
+
+void CreateTools()
+{
+ g_pSampleTool = new CGameEventTool();
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CGameEventTool::CGameEventTool()
+{
+ m_pMenuBar = NULL;
+ m_pDoc = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Init, shutdown
+//-----------------------------------------------------------------------------
+bool CGameEventTool::Init( )
+{
+ m_RecentFiles.LoadFromRegistry( GetRegistryName() );
+
+ // NOTE: This has to happen before BaseClass::Init
+ g_pVGuiLocalize->AddFile( "resource/toolgameevents_%language%.txt" );
+
+ if ( !BaseClass::Init( ) )
+ return false;
+
+ return true;
+}
+
+void CGameEventTool::Shutdown()
+{
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ BaseClass::Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get a new scheme to be applied to this tool
+//-----------------------------------------------------------------------------
+vgui::HScheme CGameEventTool::GetToolScheme()
+{
+ return vgui::scheme()->LoadSchemeFromFile( "Resource/BoxRocket.res", "SampleTool" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the menu bar
+//-----------------------------------------------------------------------------
+vgui::MenuBar *CGameEventTool::CreateMenuBar( CBaseToolSystem *pParent )
+{
+ m_pMenuBar = new CToolFileMenuBar( pParent, "Main Menu Bar" );
+
+ // Sets info in the menu bar
+ char title[ 64 ];
+ ComputeMenuBarTitle( title, sizeof( title ) );
+ m_pMenuBar->SetInfo( title );
+ m_pMenuBar->SetToolName( GetToolName() );
+
+ // Add menu buttons
+ CToolMenuButton *pFileButton = CreateToolFileMenuButton( m_pMenuBar, "File", "&File", GetActionTarget(), this );
+ CToolMenuButton *pSwitchButton = CreateToolSwitchMenuButton( m_pMenuBar, "Switcher", "&Tools", GetActionTarget() );
+
+ m_pMenuBar->AddButton( pFileButton );
+ m_pMenuBar->AddButton( pSwitchButton );
+
+ return m_pMenuBar;
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates the action menu
+//-----------------------------------------------------------------------------
+vgui::Menu *CGameEventTool::CreateActionMenu( vgui::Panel *pParent )
+{
+ vgui::Menu *pActionMenu = new Menu( pParent, "ActionMenu" );
+ pActionMenu->AddMenuItem( "#ToolHide", new KeyValues( "Command", "command", "HideActionMenu" ), GetActionTarget() );
+ return pActionMenu;
+}
+
+//-----------------------------------------------------------------------------
+// Inherited from IFileMenuCallbacks
+//-----------------------------------------------------------------------------
+int CGameEventTool::GetFileMenuItemsEnabled( )
+{
+ int nFlags = FILE_ALL;
+ if ( m_RecentFiles.IsEmpty() )
+ {
+ nFlags &= ~(FILE_RECENT | FILE_CLEAR_RECENT);
+ }
+ return nFlags;
+}
+
+void CGameEventTool::AddRecentFilesToMenu( vgui::Menu *pMenu )
+{
+ m_RecentFiles.AddToMenu( pMenu, GetActionTarget(), "OnRecent" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+void CGameEventTool::OnExit()
+{
+ enginetools->Command( "quit\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Handle commands from the action menu and other menus
+//-----------------------------------------------------------------------------
+void CGameEventTool::OnCommand( const char *cmd )
+{
+ if ( !V_stricmp( cmd, "HideActionMenu" ) )
+ {
+ if ( GetActionMenu() )
+ {
+ GetActionMenu()->SetVisible( false );
+ }
+ }
+ else if ( const char *pOnRecentSuffix = StringAfterPrefix( cmd, "OnRecent" ) )
+ {
+ int idx = Q_atoi( pOnRecentSuffix );
+ OpenFileFromHistory( idx );
+ }
+ else if( const char *pOnToolSuffix = StringAfterPrefix( cmd, "OnTool" ) )
+ {
+ int idx = Q_atoi( pOnToolSuffix );
+ enginetools->SwitchToTool( idx );
+ }
+ else
+ {
+ BaseClass::OnCommand( cmd );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Command handlers
+//-----------------------------------------------------------------------------
+void CGameEventTool::OnNew()
+{
+ if ( m_pDoc )
+ {
+ if ( m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetTXTFileName(), "xt", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnNew" ) );
+ return;
+ }
+ }
+
+ NewDocument();
+}
+
+//-----------------------------------------------------------------------------
+// Loads up a new document
+//-----------------------------------------------------------------------------
+void CGameEventTool::NewDocument( )
+{
+ Assert( !m_pDoc );
+
+ m_pDoc = new CGameEventEditDoc(/* this */);
+
+ CreateTools( m_pDoc );
+ UpdateMenuBar();
+ InitTools();
+}
+
+//-----------------------------------------------------------------------------
+// Called when the File->Open menu is selected
+//-----------------------------------------------------------------------------
+void CGameEventTool::OnOpen( )
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetTXTFileName();
+ }
+
+ OpenFile( "txt", pSaveFileName, "txt", nFlags );
+}
+
+bool CGameEventTool::OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ OnCloseNoSave();
+ if ( !LoadDocument( pFileName ) )
+ return false;
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ UpdateMenuBar();
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Updates the menu bar based on the current file
+//-----------------------------------------------------------------------------
+void CGameEventTool::UpdateMenuBar( )
+{
+ if ( !m_pDoc )
+ {
+ m_pMenuBar->SetFileName( "#CommEditNoFile" );
+ return;
+ }
+
+ const char *pTXTFile = m_pDoc->GetTXTFileName();
+ if ( !pTXTFile[0] )
+ {
+ m_pMenuBar->SetFileName( "#CommEditNoFile" );
+ return;
+ }
+
+ if ( m_pDoc->IsDirty() )
+ {
+ char sz[ 512 ];
+ Q_snprintf( sz, sizeof( sz ), "* %s", pTXTFile );
+ m_pMenuBar->SetFileName( sz );
+ }
+ else
+ {
+ m_pMenuBar->SetFileName( pTXTFile );
+ }
+}
+
+
+void CGameEventTool::OnSave()
+{
+ // FIXME: Implement
+}
+
+void CGameEventTool::OnSaveAs()
+{
+ SaveFile( NULL, NULL, 0 );
+}
+
+bool CGameEventTool::OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ // FIXME: Implement
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ return true;
+}
+
+void CGameEventTool::OnClose()
+{
+ // FIXME: Implement
+}
+
+void CGameEventTool::OnCloseNoSave()
+{
+ // FIXME: Implement
+}
+
+void CGameEventTool::OnMarkNotDirty()
+{
+ // FIXME: Implement
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the save document query dialog
+//-----------------------------------------------------------------------------
+void CGameEventTool::OpenFileFromHistory( int slot )
+{
+ const char *pFileName = m_RecentFiles.GetFile( slot );
+ OnReadFileFromDisk( pFileName, NULL, 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when file operations complete
+//-----------------------------------------------------------------------------
+void CGameEventTool::OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues )
+{
+ // FIXME: Implement
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the File browser dialog
+//-----------------------------------------------------------------------------
+void CGameEventTool::SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ char pStartingDir[ MAX_PATH ];
+ GetModSubdirectory( NULL, pStartingDir, sizeof(pStartingDir) );
+
+ pDialog->SetTitle( "Choose SampleTool .txt file", true );
+ pDialog->SetStartDirectoryContext( "sample_session", pStartingDir );
+ pDialog->AddFilter( "*.txt", "SampleTool (*.txt)", true );
+}
+
+const char *CGameEventTool::GetLogoTextureName()
+{
+ return "vgui/tools/sampletool/sampletool_logo";
+}
+
+CGameEventEditPanel *CGameEventTool::GetGameEventEditPanel()
+{
+ return m_hGameEventEditPanel.Get();
+}
+
+//-----------------------------------------------------------------------------
+// Creates
+//-----------------------------------------------------------------------------
+void CGameEventTool::CreateTools( CGameEventEditDoc *doc )
+{
+ if ( !m_hGameEventEditPanel.Get() )
+ {
+ m_hGameEventEditPanel = new CGameEventEditPanel( m_pDoc, this );
+ }
+
+ if ( !m_hConsole.Get() )
+ {
+ m_hConsole = new CConsolePage( NULL, false );
+ }
+
+ RegisterToolWindow( m_hGameEventEditPanel );
+ RegisterToolWindow( m_hConsole );
+}
+
+//-----------------------------------------------------------------------------
+// Initializes the tools
+//-----------------------------------------------------------------------------
+void CGameEventTool::InitTools()
+{
+ //ShowElementProperties();
+
+ windowposmgr->RegisterPanel( "gameeventedit", m_hGameEventEditPanel, false );
+ windowposmgr->RegisterPanel( "Console", m_hConsole, false ); // No context menu
+
+ if ( !windowposmgr->LoadPositions( "cfg/commedit.txt", this, &m_ToolWindowFactory, "CommEdit" ) )
+ {
+ OnDefaultLayout();
+ }
+
+}
+
+void CGameEventTool::DestroyTools()
+{
+ UnregisterAllToolWindows();
+
+ if ( m_hGameEventEditPanel.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hGameEventEditPanel.Get() );
+ delete m_hGameEventEditPanel.Get();
+ m_hGameEventEditPanel = NULL;
+ }
+
+ if ( m_hConsole.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hConsole.Get() );
+ delete m_hConsole.Get();
+ m_hConsole = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Loads up a new document
+//-----------------------------------------------------------------------------
+bool CGameEventTool::LoadDocument( const char *pDocName )
+{
+ Assert( !m_pDoc );
+
+ DestroyTools();
+
+ m_pDoc = new CGameEventEditDoc(/* this */);
+ if ( !m_pDoc->LoadFromFile( pDocName ) )
+ {
+ delete m_pDoc;
+ m_pDoc = NULL;
+ Warning( "Fatal error loading '%s'\n", pDocName );
+ return false;
+ }
+
+ ShowMiniViewport( true );
+
+ CreateTools( m_pDoc );
+ InitTools();
+ return true;
+}
+
+CConsolePage *CGameEventTool::GetConsole()
+{
+ return m_hConsole;
+}
+
+
+void CGameEventTool::ShowToolWindow( Panel *tool, char const *toolName, bool visible )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL && visible )
+ {
+ m_ToolWindowFactory.InstanceToolWindow( this, false, tool, toolName, false );
+ }
+ else if ( !visible )
+ {
+ ToolWindow *tw = dynamic_cast< ToolWindow * >( tool->GetParent()->GetParent() );
+ Assert( tw );
+ tw->RemovePage( tool );
+ }
+}
+
+void CGameEventTool::ToggleToolWindow( Panel *tool, char const *toolName )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL )
+ {
+ ShowToolWindow( tool, toolName, true );
+ }
+ else
+ {
+ ShowToolWindow( tool, toolName, false );
+ }
+}
+
+
+void CGameEventTool::OnToggleConsole()
+{
+ if ( m_hConsole.Get() )
+ {
+ ToggleToolWindow( m_hConsole.Get(), "#BxConsole" );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets up the default layout
+//-----------------------------------------------------------------------------
+void CGameEventTool::OnDefaultLayout()
+{
+ int y = m_pMenuBar->GetTall();
+
+ int usew, useh;
+ GetSize( usew, useh );
+
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+
+ Assert( ToolWindow::GetToolWindowCount() == 0 );
+
+ CGameEventEditPanel *pEditPanel = GetGameEventEditPanel();
+ CConsolePage *pConsole = GetConsole();
+
+ // Need three containers
+ ToolWindow *pEditPanelWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, pEditPanel, "#CommEditProperties", false );
+ ToolWindow *pMiniViewport = dynamic_cast< ToolWindow* >( GetMiniViewport() );
+ pMiniViewport->AddPage( pConsole, "#BxConsole", false );
+
+ int quarterScreen = usew / 4;
+ SetMiniViewportBounds( quarterScreen, y, 3*quarterScreen, useh - y );
+ pEditPanelWindow->SetBounds( 0, y, quarterScreen, useh - y );
+}
+
+
diff --git a/tools/gameevents/gameevents.vpc b/tools/gameevents/gameevents.vpc
new file mode 100644
index 0000000..406171f
--- /dev/null
+++ b/tools/gameevents/gameevents.vpc
@@ -0,0 +1,60 @@
+//-----------------------------------------------------------------------------
+// GAMEEVENTS.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin\tools"
+
+$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE,.\,..\common,$SRCDIR\game\shared"
+ $PreprocessorDefinitions "$BASE;GAMEEVENTS_EXPORTS"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "$BASE Psapi.lib"
+ }
+}
+
+$Project "GameEvents"
+{
+ $Folder "Source Files"
+ {
+ $File "gameevents.cpp"
+ $File "gameeventeditdoc.cpp"
+ $File "gameeventeditpanel.cpp"
+
+ $File "$SRCDIR\public\interpolatortypes.cpp"
+ $File "$SRCDIR\public\registry.cpp"
+ $File "$SRCDIR\public\vgui_controls\vgui_controls.cpp"
+ }
+
+ $Folder "Header Files"
+ {
+ $File "gameeventeditdoc.h"
+ $File "gameeventeditpanel.h"
+ $File "$SRCDIR\public\mathlib\mathlib.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib datamodel
+ $Lib dme_controls
+ $Lib dmserializers
+ $Lib mathlib
+ $Lib matsys_controls
+ $Lib movieobjects
+ $Lib sfmobjects
+ $Lib tier2
+ $Lib tier3
+ $Lib toolutils
+ $Lib vgui_controls
+ }
+}
diff --git a/tools/pet/particlesystemdefinitionbrowser.cpp b/tools/pet/particlesystemdefinitionbrowser.cpp
new file mode 100644
index 0000000..1924c30
--- /dev/null
+++ b/tools/pet/particlesystemdefinitionbrowser.cpp
@@ -0,0 +1,599 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Singleton dialog that generates and presents the entity report.
+//
+//===========================================================================//
+
+#include "particlesystemdefinitionbrowser.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "iregistry.h"
+#include "vgui/ivgui.h"
+#include "vgui_controls/listpanel.h"
+#include "vgui_controls/inputdialog.h"
+#include "vgui_controls/messagebox.h"
+#include "petdoc.h"
+#include "pettool.h"
+#include "datamodel/dmelement.h"
+#include "vgui/keycode.h"
+#include "dme_controls/dmecontrols_utils.h"
+#include "dme_controls/particlesystempanel.h"
+#include "filesystem.h"
+#include "vgui_controls/FileOpenDialog.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Sort by particle system definition name
+//-----------------------------------------------------------------------------
+static int __cdecl ParticleSystemNameSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ const char *string1 = item1.kv->GetString("name");
+ const char *string2 = item2.kv->GetString("name");
+ return Q_stricmp( string1, string2 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CParticleSystemDefinitionBrowser::CParticleSystemDefinitionBrowser( CPetDoc *pDoc, vgui::Panel* pParent, const char *pName )
+ : BaseClass( pParent, pName ), m_pDoc( pDoc )
+{
+ SetKeyBoardInputEnabled( true );
+ SetPaintBackgroundEnabled( true );
+
+ m_pParticleSystemsDefinitions = new vgui::ListPanel( this, "ParticleSystems" );
+ m_pParticleSystemsDefinitions->AddColumnHeader( 0, "name", "Name", 52, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pParticleSystemsDefinitions->SetColumnSortable( 0, true );
+ m_pParticleSystemsDefinitions->SetEmptyListText( "No Particle System Definitions" );
+ m_pParticleSystemsDefinitions->AddActionSignalTarget( this );
+ m_pParticleSystemsDefinitions->SetSortFunc( 0, ParticleSystemNameSortFunc );
+ m_pParticleSystemsDefinitions->SetSortColumn( 0 );
+
+ LoadControlSettingsAndUserConfig( "resource/particlesystemdefinitionbrowser.res" );
+
+ UpdateParticleSystemList();
+}
+
+CParticleSystemDefinitionBrowser::~CParticleSystemDefinitionBrowser()
+{
+ SaveUserConfig();
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the ith selected particle system
+//-----------------------------------------------------------------------------
+CDmeParticleSystemDefinition* CParticleSystemDefinitionBrowser::GetSelectedParticleSystem( int i )
+{
+ int iSel = m_pParticleSystemsDefinitions->GetSelectedItem( i );
+ KeyValues *kv = m_pParticleSystemsDefinitions->GetItem( iSel );
+ return GetElementKeyValue< CDmeParticleSystemDefinition >( kv, "particleSystem" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Deletes the marked objects.
+//-----------------------------------------------------------------------------
+void CParticleSystemDefinitionBrowser::DeleteParticleSystems()
+{
+ int iSel = m_pParticleSystemsDefinitions->GetSelectedItem( 0 );
+ int nRow = m_pParticleSystemsDefinitions->GetItemCurrentRow( iSel ) - 1;
+ {
+ // This is undoable
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Delete Particle Systems", "Delete Particle Systems" );
+
+ //
+ // Build a list of objects to delete.
+ //
+ CUtlVector< CDmeParticleSystemDefinition* > itemsToDelete;
+ int nCount = m_pParticleSystemsDefinitions->GetSelectedItemsCount();
+ for (int i = 0; i < nCount; i++)
+ {
+ CDmeParticleSystemDefinition *pParticleSystem = GetSelectedParticleSystem( i );
+ if ( pParticleSystem )
+ {
+ itemsToDelete.AddToTail( pParticleSystem );
+ }
+ }
+
+ nCount = itemsToDelete.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ m_pDoc->DeleteParticleSystemDefinition( itemsToDelete[i] );
+ }
+ }
+
+ // Update the list box selection.
+ if ( m_pParticleSystemsDefinitions->GetItemCount() > 0 )
+ {
+ if ( nRow < 0 )
+ {
+ nRow = 0;
+ }
+ else if ( nRow >= m_pParticleSystemsDefinitions->GetItemCount() )
+ {
+ nRow = m_pParticleSystemsDefinitions->GetItemCount() - 1;
+ }
+
+ iSel = m_pParticleSystemsDefinitions->GetItemIDFromRow( nRow );
+ m_pParticleSystemsDefinitions->SetSingleSelectedItem( iSel );
+ }
+ else
+ {
+ m_pParticleSystemsDefinitions->ClearSelectedItems();
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CParticleSystemDefinitionBrowser::LoadKVSection( CDmeParticleSystemDefinition *pNew, KeyValues *pOverridesKv, ParticleFunctionType_t eType )
+{
+ // Operator KV
+ KeyValues *pOperator = pOverridesKv->FindKey( GetParticleFunctionTypeName(eType), NULL );
+ if ( !pOperator )
+ return;
+
+ // Function
+ FOR_EACH_TRUE_SUBKEY( pOperator, pFunctionBlock )
+ {
+ int iFunction = pNew->FindFunction( eType, pFunctionBlock->GetName() );
+ if ( iFunction >= 0 )
+ {
+ CDmeParticleFunction *pDmeFunction = pNew->GetParticleFunction( eType, iFunction );
+ // Elements
+ FOR_EACH_SUBKEY( pFunctionBlock, pAttributeItem )
+ {
+ CDmAttribute *pAttribute = pDmeFunction->GetAttribute( pAttributeItem->GetName() );
+ if ( !pAttribute )
+ {
+ Warning( "Unable to Find Attribute [%s] in Function [%s] in Operator [%s] for Definition [%s]\n", pAttributeItem->GetName(), pFunctionBlock->GetName(), GetParticleFunctionTypeName(eType), pNew->GetName() );
+ }
+ else
+ {
+ pAttribute->SetValueFromString( pAttributeItem->GetString() );
+ }
+ }
+ }
+ else
+ {
+ Warning( "Function [%s] not found under Operator [%s] for Definition [%s]\n", pFunctionBlock->GetName(), GetParticleFunctionTypeName(eType), pNew->GetName() );
+ }
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// Given a KV, create, add and return an effect
+//-----------------------------------------------------------------------------
+CDmeParticleSystemDefinition* CParticleSystemDefinitionBrowser::CreateParticleFromKV( KeyValues *pKeyValue )
+{
+ CDmeParticleSystemDefinition* pBaseParticleDef = NULL;
+
+ // Get the Base Particle Effect Def
+ const char* pBaseParticleName = pKeyValue->GetString( "base_effect", "" );
+ for ( int i = 0; i < m_pParticleSystemsDefinitions->GetItemCount(); ++i )
+ {
+ KeyValues *kv = m_pParticleSystemsDefinitions->GetItem( i );
+ if ( !V_strcmp( kv->GetString( "name", "" ), pBaseParticleName ) )
+ {
+ //
+ pBaseParticleDef = GetElementKeyValue< CDmeParticleSystemDefinition >( kv, "particleSystem" );
+ break;
+ }
+ }
+
+ // Base Particle could not be found, end;
+ if ( !pBaseParticleDef )
+ {
+ Warning( "Unable to to find base particle system [%s]", pBaseParticleName );
+ return NULL;
+ }
+
+ // Create a Copy of the Base Effect
+ const char *pszNewParticleName = pKeyValue->GetName();
+ //CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Copy Particle System", "Copy Particle System" );
+ CDmeParticleSystemDefinition *pNew = CastElement<CDmeParticleSystemDefinition>( pBaseParticleDef->Copy() );
+ pNew->SetName( pszNewParticleName );
+
+ // Overrides
+ //
+ //"properties"
+ KeyValues *pProperties = pKeyValue->FindKey( "Properties", NULL );
+ if ( pProperties )
+ {
+ FOR_EACH_SUBKEY( pProperties, pProperty )
+ {
+ CDmAttribute *pAttribute = pNew->GetAttribute( pProperty->GetName() );
+ if ( !pAttribute )
+ {
+ Warning( "Unable to Find Attribute [%s] in Function [%s]\n", pProperty->GetName(), "Properties" );
+ }
+ else
+ {
+ pAttribute->SetValueFromString( pProperty->GetString() );
+ }
+ }
+ }
+
+ LoadKVSection( pNew, pKeyValue, FUNCTION_RENDERER );
+ LoadKVSection( pNew, pKeyValue, FUNCTION_OPERATOR );
+ LoadKVSection( pNew, pKeyValue, FUNCTION_INITIALIZER );
+ LoadKVSection( pNew, pKeyValue, FUNCTION_EMITTER );
+ LoadKVSection( pNew, pKeyValue, FUNCTION_FORCEGENERATOR );
+ LoadKVSection( pNew, pKeyValue, FUNCTION_CONSTRAINT );
+
+ // Remove copied children
+ int iChildrenCount = pNew->GetParticleFunctionCount( FUNCTION_CHILDREN );
+ for ( int i = iChildrenCount - 1; i >= 0; i-- )
+ {
+ pNew->RemoveFunction( FUNCTION_CHILDREN, i );
+ }
+
+ // Search Children
+ KeyValues *pChildren = pKeyValue->FindKey( "Children", NULL );
+ if ( pChildren )
+ {
+ FOR_EACH_TRUE_SUBKEY( pChildren, pChild )
+ {
+ // each Child is its own effect so we need to add it and return it
+ CDmeParticleSystemDefinition* pChildEffect = CreateParticleFromKV( pChild );
+ if ( pChildEffect )
+ {
+ pNew->AddChild( pChildEffect );
+ }
+ }
+ }
+
+ m_pDoc->ReplaceParticleSystemDefinition( pNew );
+ m_pDoc->UpdateAllParticleSystems();
+ return pNew;
+}
+//-----------------------------------------------------------------------------
+// Create from KV
+void CParticleSystemDefinitionBrowser::CreateParticleSystemsFromKV( const char *pFileName )
+{
+ //
+ //const char * pFileName = "particles\\_weapon_prefab_override_kv.txt";
+
+ CUtlBuffer bufRawData;
+ bool bReadFileOK = g_pFullFileSystem->ReadFile( pFileName, "MOD", bufRawData );
+ if ( !bReadFileOK )
+ {
+ Warning( "Unable to Open KV file [%s]\n", pFileName );
+ return;
+ }
+
+ // Wrap it with a text buffer reader
+ CUtlBuffer bufText( bufRawData.Base(), bufRawData.TellPut(), CUtlBuffer::READ_ONLY | CUtlBuffer::TEXT_BUFFER );
+
+ KeyValues *pBaseKeyValue = NULL;
+ pBaseKeyValue = new KeyValues( "CCreateParticlesFromKV" );
+
+ if ( !pBaseKeyValue->LoadFromBuffer( NULL, bufText ) )
+ {
+ Warning( "Unable to Read KV file [%s]\n", pFileName );
+ pBaseKeyValue->deleteThis();
+ return;
+ }
+
+ FOR_EACH_TRUE_SUBKEY( pBaseKeyValue, pKVOver )
+ {
+ CreateParticleFromKV( pKVOver );
+ }
+
+}
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CParticleSystemDefinitionBrowser::OnKeyCodeTyped( vgui::KeyCode code )
+{
+ if ( code == KEY_DELETE )
+ {
+ DeleteParticleSystems();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped( code );
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CParticleSystemDefinitionBrowser::OnFileSelected(const char *fullpath)
+{
+ CreateParticleSystemsFromKV( fullpath );
+}
+//-----------------------------------------------------------------------------
+// Called when the selection changes
+//-----------------------------------------------------------------------------
+void CParticleSystemDefinitionBrowser::UpdateParticleSystemSelection()
+{
+ if ( m_pParticleSystemsDefinitions->GetSelectedItemsCount() == 1 )
+ {
+ CDmeParticleSystemDefinition *pParticleSystem = GetSelectedParticleSystem( 0 );
+ g_pPetTool->SetCurrentParticleSystem( pParticleSystem, false );
+ }
+ else
+ {
+ g_pPetTool->SetCurrentParticleSystem( NULL, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Item selection/deselection
+//-----------------------------------------------------------------------------
+void CParticleSystemDefinitionBrowser::OnItemSelected( void )
+{
+ UpdateParticleSystemSelection();
+}
+
+void CParticleSystemDefinitionBrowser::OnItemDeselected( void )
+{
+ UpdateParticleSystemSelection();
+}
+
+
+//-----------------------------------------------------------------------------
+// Select a particular node
+//-----------------------------------------------------------------------------
+void CParticleSystemDefinitionBrowser::SelectParticleSystem( CDmeParticleSystemDefinition *pFind )
+{
+ m_pParticleSystemsDefinitions->ClearSelectedItems();
+ for ( int nItemID = m_pParticleSystemsDefinitions->FirstItem(); nItemID != m_pParticleSystemsDefinitions->InvalidItemID(); nItemID = m_pParticleSystemsDefinitions->NextItem( nItemID ) )
+ {
+ KeyValues *kv = m_pParticleSystemsDefinitions->GetItem( nItemID );
+ CDmeParticleSystemDefinition *pParticleSystem = GetElementKeyValue<CDmeParticleSystemDefinition>( kv, "particleSystem" );
+ if ( pParticleSystem == pFind )
+ {
+ m_pParticleSystemsDefinitions->AddSelectedItem( nItemID );
+ break;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when buttons are clicked
+//-----------------------------------------------------------------------------
+void CParticleSystemDefinitionBrowser::OnInputCompleted( KeyValues *pKeyValues )
+{
+ const char *pText = pKeyValues->GetString( "text", NULL );
+ if ( m_pDoc->IsParticleSystemDefined( pText ) )
+ {
+ char pBuf[1024];
+ Q_snprintf( pBuf, sizeof(pBuf), "Particle System \"%s\" already exists!\n", pText );
+ vgui::MessageBox *pMessageBox = new vgui::MessageBox( "Duplicate Particle System Name!\n", pBuf, g_pPetTool->GetRootPanel() );
+ pMessageBox->DoModal( );
+ return;
+ }
+
+ if ( pKeyValues->FindKey( "create" ) )
+ {
+ CDmeParticleSystemDefinition *pParticleSystem = m_pDoc->AddNewParticleSystemDefinition( pText );
+ g_pPetTool->SetCurrentParticleSystem( pParticleSystem );
+ }
+ else if ( pKeyValues->FindKey( "copy" ) )
+ {
+ int nCount = m_pParticleSystemsDefinitions->GetSelectedItemsCount();
+ if ( nCount )
+ {
+ CDmeParticleSystemDefinition *pParticleSystem = GetSelectedParticleSystem( 0 );
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Copy Particle System",
+ "Copy Particle System" );
+ CDmeParticleSystemDefinition * pNew =
+ CastElement<CDmeParticleSystemDefinition>( pParticleSystem->Copy( ) );
+ pNew->SetName( pText );
+ m_pDoc->AddNewParticleSystemDefinition( pNew, guard );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Copy to clipboard
+//-----------------------------------------------------------------------------
+void CParticleSystemDefinitionBrowser::CopyToClipboard( )
+{
+ int nCount = m_pParticleSystemsDefinitions->GetSelectedItemsCount();
+
+ CUtlVector< KeyValues * > list;
+ CUtlRBTree< CDmeParticleSystemDefinition* > defs( 0, 0, DefLessFunc( CDmeParticleSystemDefinition* ) );
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeParticleSystemDefinition *pParticleSystem = GetSelectedParticleSystem( i );
+
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+ if ( g_pDataModel->Serialize( buf, "keyvalues2", "pcf", pParticleSystem->GetHandle() ) )
+ {
+ KeyValues *pData = new KeyValues( "Clipboard" );
+ pData->SetString( "pcf", (char*)buf.Base() );
+ list.AddToTail( pData );
+ }
+ }
+
+ if ( list.Count() )
+ {
+ g_pDataModel->SetClipboardData( list );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Paste from clipboard
+//-----------------------------------------------------------------------------
+void CParticleSystemDefinitionBrowser::ReplaceDef_r( CUndoScopeGuard& guard, CDmeParticleSystemDefinition *pDef )
+{
+ if ( !pDef )
+ return;
+
+ m_pDoc->ReplaceParticleSystemDefinition( pDef );
+ int nChildCount = pDef->GetParticleFunctionCount( FUNCTION_CHILDREN );
+ for ( int i = 0; i < nChildCount; ++i )
+ {
+ CDmeParticleChild *pChildFunction = static_cast< CDmeParticleChild* >( pDef->GetParticleFunction( FUNCTION_CHILDREN, i ) );
+ CDmeParticleSystemDefinition* pChild = pChildFunction->m_Child;
+ ReplaceDef_r( guard, pChild );
+ }
+}
+
+void CParticleSystemDefinitionBrowser::PasteFromClipboard( )
+{
+ // This is undoable
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Paste From Clipboard", "Paste From Clipboard" );
+
+ bool bRefreshAll = false;
+ CUtlVector< KeyValues * > list;
+ g_pDataModel->GetClipboardData( list );
+ int nItems = list.Count();
+ for ( int i = 0; i < nItems; ++i )
+ {
+ const char *pData = list[i]->GetString( "pcf" );
+ if ( !pData )
+ continue;
+
+ int nLen = Q_strlen( pData );
+ CUtlBuffer buf( pData, nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY );
+
+ DmElementHandle_t hRoot;
+ if ( !g_pDataModel->Unserialize( buf, "keyvalues2", "pcf", NULL, "paste", CR_FORCE_COPY, hRoot ) )
+ continue;
+
+ CDmeParticleSystemDefinition *pDef = GetElement<CDmeParticleSystemDefinition>( hRoot );
+ if ( !pDef )
+ continue;
+
+ ReplaceDef_r( guard, pDef );
+ bRefreshAll = true;
+ }
+
+ guard.Release();
+
+ if ( bRefreshAll )
+ {
+ m_pDoc->UpdateAllParticleSystems();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when buttons are clicked
+//-----------------------------------------------------------------------------
+void CParticleSystemDefinitionBrowser::OnCommand( const char *pCommand )
+{
+ if ( !Q_stricmp( pCommand, "create" ) )
+ {
+ vgui::InputDialog *pInputDialog = new vgui::InputDialog( g_pPetTool->GetRootPanel(), "Enter Particle System Name", "Name:", "" );
+ pInputDialog->SetSmallCaption( true );
+ pInputDialog->SetMultiline( false );
+ pInputDialog->AddActionSignalTarget( this );
+ pInputDialog->DoModal( new KeyValues("create") );
+ return;
+ }
+ if ( !Q_stricmp( pCommand, "copy" ) )
+ {
+ vgui::InputDialog *pInputDialog = new vgui::InputDialog( g_pPetTool->GetRootPanel(), "Enter Particle System Name", "Name:", "" );
+ pInputDialog->SetSmallCaption( true );
+ pInputDialog->SetMultiline( false );
+ pInputDialog->AddActionSignalTarget( this );
+ pInputDialog->DoModal( new KeyValues("copy") );
+ return;
+ }
+ if ( !Q_stricmp( pCommand, "Create From KeyValue" ) )
+ {
+ vgui::FileOpenDialog *pDialog = new vgui::FileOpenDialog( g_pPetTool->GetRootPanel(), "Select KV File", vgui::FOD_OPEN );
+ pDialog->SetTitle( "Choose KeyValue File", true );
+ pDialog->AddFilter( "*.txt", "KeyValue File (*.txt)", true );
+ pDialog->AddActionSignalTarget( this );
+
+ char szParticlesDir[MAX_PATH];
+ pDialog->SetStartDirectory( g_pFullFileSystem->RelativePathToFullPath( "particles", "MOD", szParticlesDir, sizeof(szParticlesDir) ) );
+ pDialog->DoModal( new KeyValues( "Create From KeyValue" ) );
+
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "delete" ) )
+ {
+ DeleteParticleSystems();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "Save" ) )
+ {
+ g_pPetTool->Save();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "SaveAndTest" ) )
+ {
+ g_pPetTool->SaveAndTest();
+ return;
+ }
+
+ BaseClass::OnCommand( pCommand );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CParticleSystemDefinitionBrowser::UpdateParticleSystemList(void)
+{
+ const CDmrParticleSystemList particleSystemList = m_pDoc->GetParticleSystemDefinitionList();
+ if ( !particleSystemList.IsValid() )
+ return;
+
+ // Maintain selection if possible
+ CUtlVector< CUtlString > selectedItems;
+ int nCount = m_pParticleSystemsDefinitions->GetSelectedItemsCount();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeParticleSystemDefinition *pParticleSystem = GetSelectedParticleSystem( i );
+ if ( pParticleSystem )
+ {
+ selectedItems.AddToTail( pParticleSystem->GetName() );
+ }
+ }
+
+ m_pParticleSystemsDefinitions->RemoveAll();
+ int nSelectedItemCount = selectedItems.Count();
+ nCount = particleSystemList.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeParticleSystemDefinition *pParticleSystem = particleSystemList[i];
+ if ( !pParticleSystem )
+ continue;
+
+ const char *pName = pParticleSystem->GetName();
+ if ( !pName || !pName[0] )
+ {
+ pName = "<no name>";
+ }
+
+ KeyValues *kv = new KeyValues( "node" );
+ kv->SetString( "name", pName );
+ SetElementKeyValue( kv, "particleSystem", pParticleSystem );
+
+ int nItemID = m_pParticleSystemsDefinitions->AddItem( kv, 0, false, false );
+
+ for ( int j = 0; j < nSelectedItemCount; ++j )
+ {
+ if ( Q_stricmp( selectedItems[j], pName ) )
+ continue;
+
+ m_pParticleSystemsDefinitions->AddSelectedItem( nItemID );
+ selectedItems.FastRemove(j);
+ --nSelectedItemCount;
+ break;
+ }
+ }
+ m_pParticleSystemsDefinitions->SortList();
+}
+
diff --git a/tools/pet/particlesystemdefinitionbrowser.h b/tools/pet/particlesystemdefinitionbrowser.h
new file mode 100644
index 0000000..725b2a1
--- /dev/null
+++ b/tools/pet/particlesystemdefinitionbrowser.h
@@ -0,0 +1,90 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#ifndef PARTICLESYSTEMDEFINITIONBROWSER_H
+#define PARTICLESYSTEMDEFINITIONBROWSER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/editablepanel.h"
+#include "tier1/utlstring.h"
+#include "particles/particles.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CPetDoc;
+class CDmeParticleSystemDefinition;
+class CUndoScopeGuard;
+namespace vgui
+{
+ class ComboBox;
+ class Button;
+ class TextEntry;
+ class ListPanel;
+ class CheckButton;
+ class RadioButton;
+}
+
+
+//-----------------------------------------------------------------------------
+// Panel that shows all entities in the level
+//-----------------------------------------------------------------------------
+class CParticleSystemDefinitionBrowser : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CParticleSystemDefinitionBrowser, vgui::EditablePanel );
+
+public:
+ CParticleSystemDefinitionBrowser( CPetDoc *pDoc, vgui::Panel* pParent, const char *pName ); // standard constructor
+ virtual ~CParticleSystemDefinitionBrowser();
+
+ // Inherited from Panel
+ virtual void OnCommand( const char *pCommand );
+ virtual void OnKeyCodeTyped( vgui::KeyCode code );
+ MESSAGE_FUNC_CHARPTR( OnFileSelected, "FileSelected", fullpath );
+ // Methods related to updating the listpanel
+ void UpdateParticleSystemList();
+
+ // Select a particular node
+ void SelectParticleSystem( CDmeParticleSystemDefinition *pParticleSystem );
+
+ // Copy, paste.
+ void CopyToClipboard( );
+ void PasteFromClipboard( );
+
+private:
+ // Messages handled
+ MESSAGE_FUNC( OnItemDeselected, "ItemDeselected" );
+ MESSAGE_FUNC( OnItemSelected, "ItemSelected" );
+ MESSAGE_FUNC_PARAMS( OnInputCompleted, "InputCompleted", kv );
+
+ void ReplaceDef_r( CUndoScopeGuard& guard, CDmeParticleSystemDefinition *pDef );
+
+ // Gets the ith selected particle system
+ CDmeParticleSystemDefinition* GetSelectedParticleSystem( int i );
+
+ // Called when the selection changes
+ void UpdateParticleSystemSelection();
+
+ // Deletes selected particle systems
+ void DeleteParticleSystems();
+
+ // Create from KV
+ void LoadKVSection( CDmeParticleSystemDefinition *pNew, KeyValues *pOverridesKv, ParticleFunctionType_t eType );
+ CDmeParticleSystemDefinition* CreateParticleFromKV( KeyValues *pKeyValue );
+ void CreateParticleSystemsFromKV( const char *pFilepath );
+
+ // Shows the most recent selected object in properties window
+ void OnProperties();
+
+ CPetDoc *m_pDoc;
+ vgui::ListPanel *m_pParticleSystemsDefinitions;
+};
+
+
+#endif // PARTICLESYSTEMDEFINITIONBROWSER_H
diff --git a/tools/pet/particlesystempropertiescontainer.cpp b/tools/pet/particlesystempropertiescontainer.cpp
new file mode 100644
index 0000000..58ee419
--- /dev/null
+++ b/tools/pet/particlesystempropertiescontainer.cpp
@@ -0,0 +1,73 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Dialog used to edit properties of a particle system definition
+//
+//===========================================================================//
+
+#include "ParticleSystemPropertiesContainer.h"
+#include "petdoc.h"
+#include "pettool.h"
+#include "datamodel/dmelement.h"
+#include "movieobjects/dmeparticlesystemdefinition.h"
+#include "dme_controls/dmecontrols_utils.h"
+#include "dme_controls/particlesystempanel.h"
+
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+#pragma warning (disable:4355)
+CParticleSystemPropertiesContainer::CParticleSystemPropertiesContainer( CPetDoc *pDoc, vgui::Panel* pParent ) :
+ BaseClass( this, pParent ), m_pDoc( pDoc )
+{
+}
+#pragma warning (default:4355)
+
+
+//-----------------------------------------------------------------------------
+// Refreshes the list of raw controls
+//-----------------------------------------------------------------------------
+void CParticleSystemPropertiesContainer::GetKnownParticleDefinitions( CUtlVector< CDmeParticleSystemDefinition* > &definitions )
+{
+ definitions.RemoveAll();
+
+ CDmrParticleSystemList particleSystemList = g_pPetTool->GetDocument()->GetParticleSystemDefinitionList();
+ if ( !particleSystemList.IsValid() )
+ return;
+
+ int nCount = particleSystemList.Count();
+ definitions.EnsureCapacity( nCount );
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeParticleSystemDefinition *pParticleSystem = particleSystemList[i];
+ definitions.AddToTail( pParticleSystem );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Called when the base class changes anything at all in the particle system
+//-----------------------------------------------------------------------------
+void CParticleSystemPropertiesContainer::OnParticleSystemModified()
+{
+ CAppNotifyScopeGuard sg( "CParticleSystemPropertiesContainer::OnParticleSystemModified", NOTIFY_SETDIRTYFLAG );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when the selected particle function changes
+//-----------------------------------------------------------------------------
+void CParticleSystemPropertiesContainer::OnParticleFunctionSelChanged( KeyValues *pParams )
+{
+ if ( g_pPetTool->GetParticlePreview() )
+ {
+ CDmeParticleFunction *pFunction = GetElementKeyValue<CDmeParticleFunction>( pParams, "function" );
+ g_pPetTool->GetParticlePreview()->SetParticleFunction( pFunction );
+ }
+}
+
diff --git a/tools/pet/particlesystempropertiescontainer.h b/tools/pet/particlesystempropertiescontainer.h
new file mode 100644
index 0000000..26ac3f8
--- /dev/null
+++ b/tools/pet/particlesystempropertiescontainer.h
@@ -0,0 +1,45 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Dialog used to edit properties of a particle system definition
+//
+//===========================================================================//
+
+#ifndef PARTICLESYSTEMPROPERTIESCONTAINER_H
+#define PARTICLESYSTEMPROPERTIESCONTAINER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "dme_controls/particlesystempropertiespanel.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CPetDoc;
+
+
+//-----------------------------------------------------------------------------
+// Panel used to edit a particle system definition
+//-----------------------------------------------------------------------------
+class CParticleSystemPropertiesContainer : public CParticleSystemPropertiesPanel, public IParticleSystemPropertiesPanelQuery
+{
+ DECLARE_CLASS_SIMPLE( CParticleSystemPropertiesContainer, CParticleSystemPropertiesPanel );
+
+public:
+ CParticleSystemPropertiesContainer( CPetDoc *pDoc, vgui::Panel* pParent ); // standard constructor
+
+ // Inherited from IParticleSystemPropertiesPanelQuery
+ virtual void GetKnownParticleDefinitions( CUtlVector< CDmeParticleSystemDefinition* > &definitions );
+
+private:
+ MESSAGE_FUNC_PARAMS( OnParticleFunctionSelChanged, "ParticleFunctionSelChanged", params );
+
+ // For inheriting classes to get notified without having to listen to messages
+ virtual void OnParticleSystemModified();
+
+ CPetDoc *m_pDoc;
+};
+
+
+#endif // PARTICLESYSTEMPROPERTIESCONTAINER_H
diff --git a/tools/pet/pet.vpc b/tools/pet/pet.vpc
new file mode 100644
index 0000000..af3bd54
--- /dev/null
+++ b/tools/pet/pet.vpc
@@ -0,0 +1,64 @@
+//-----------------------------------------------------------------------------
+// PET.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin\tools"
+
+$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE,.\,$SRCDIR\game\shared"
+ $PreprocessorDefinitions "$BASE;PET_EXPORTS"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "$BASE Psapi.lib"
+ }
+}
+
+$Project "Pet"
+{
+ $Folder "Source Files"
+ {
+ $File "$SRCDIR\public\interpolatortypes.cpp"
+ $File "particlesystemdefinitionbrowser.cpp"
+ $File "particlesystempropertiescontainer.cpp"
+ $File "petdoc.cpp"
+ $File "pettool.cpp"
+ $File "$SRCDIR\public\registry.cpp"
+ $File "$SRCDIR\public\vgui_controls\vgui_controls.cpp"
+ }
+
+ $Folder "Header Files"
+ {
+ $File "$SRCDIR\public\mathlib\mathlib.h"
+ $File "particlesystemdefinitionbrowser.h"
+ $File "particlesystempropertiescontainer.h"
+ $File "petdoc.h"
+ $File "pettool.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib datamodel
+ $Lib dme_controls
+ $Lib dmserializers
+ $Lib dmxloader
+ $Lib mathlib
+ $Lib matsys_controls
+ $Lib movieobjects
+ $Lib particles
+ $Lib sfmobjects
+ $Lib tier2
+ $Lib tier3
+ $Lib toolutils
+ $Lib vgui_controls
+ }
+}
diff --git a/tools/pet/petdoc.cpp b/tools/pet/petdoc.cpp
new file mode 100644
index 0000000..707a77a
--- /dev/null
+++ b/tools/pet/petdoc.cpp
@@ -0,0 +1,536 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "petdoc.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "toolutils/enginetools_int.h"
+#include "filesystem.h"
+#include "pettool.h"
+#include "toolframework/ienginetool.h"
+#include "movieobjects/dmeparticlesystemdefinition.h"
+#include "datamodel/idatamodel.h"
+#include "toolutils/attributeelementchoicelist.h"
+#include "particlesystemdefinitionbrowser.h"
+#include "vgui_controls/messagebox.h"
+#include "particles/particles.h"
+#include "particlesystempropertiescontainer.h"
+#include "dme_controls/particlesystempanel.h"
+#include "dme_controls/dmecontrols.h"
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CPetDoc::CPetDoc( IPetDocCallback *pCallback ) : m_pCallback( pCallback )
+{
+ m_hRoot = NULL;
+ m_pFileName[0] = 0;
+ m_bDirty = false;
+ g_pDataModel->InstallNotificationCallback( this );
+ SetElementPropertiesChoices( this );
+}
+
+CPetDoc::~CPetDoc()
+{
+ if ( m_hRoot.Get() )
+ {
+ g_pDataModel->RemoveFileId( m_hRoot->GetFileId() );
+ m_hRoot = NULL;
+ }
+ g_pDataModel->RemoveNotificationCallback( this );
+ SetElementPropertiesChoices( NULL );
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from INotifyUI
+//-----------------------------------------------------------------------------
+void CPetDoc::NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ OnDataChanged( pReason, nNotifySource, nNotifyFlags );
+}
+
+
+bool CPetDoc::GetIntChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, IntChoiceList_t &list )
+{
+ if ( !Q_stricmp( pChoiceListType, "particlefield" ) )
+ {
+ for ( int i = 0; i < MAX_PARTICLE_ATTRIBUTES; ++i )
+ {
+ const char *pName = g_pParticleSystemMgr->GetParticleFieldName( i );
+ if ( pName )
+ {
+ int j = list.AddToTail();
+ list[j].m_nValue = i;
+ list[j].m_pChoiceString = pName;
+ }
+ }
+ return true;
+ }
+
+ if ( !Q_stricmp( pChoiceListType, "particlefield_scalar" ) )
+ {
+ for ( int i = 0; i < MAX_PARTICLE_ATTRIBUTES; ++i )
+ {
+ if ( ( ATTRIBUTES_WHICH_ARE_VEC3S_MASK & ( 1 << i ) ) != 0 )
+ continue;
+
+ const char *pName = g_pParticleSystemMgr->GetParticleFieldName( i );
+ if ( pName )
+ {
+ int j = list.AddToTail();
+ list[j].m_nValue = i;
+ list[j].m_pChoiceString = pName;
+ }
+ }
+ return true;
+ }
+
+ if ( !Q_stricmp( pChoiceListType, "particlefield_vector" ) )
+ {
+ for ( int i = 0; i < MAX_PARTICLE_ATTRIBUTES; ++i )
+ {
+ if ( ( ATTRIBUTES_WHICH_ARE_VEC3S_MASK & ( 1 << i ) ) == 0 )
+ continue;
+
+ const char *pName = g_pParticleSystemMgr->GetParticleFieldName( i );
+ if ( pName )
+ {
+ int j = list.AddToTail();
+ list[j].m_nValue = i;
+ list[j].m_pChoiceString = pName;
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the file name
+//-----------------------------------------------------------------------------
+const char *CPetDoc::GetFileName()
+{
+ return m_pFileName;
+}
+
+void CPetDoc::SetFileName( const char *pFileName )
+{
+ Q_strncpy( m_pFileName, pFileName, sizeof( m_pFileName ) );
+ Q_FixSlashes( m_pFileName );
+ SetDirty( true );
+}
+
+//-----------------------------------------------------------------------------
+// Dirty bits
+//-----------------------------------------------------------------------------
+void CPetDoc::SetDirty( bool bDirty )
+{
+ m_bDirty = bDirty;
+}
+
+bool CPetDoc::IsDirty() const
+{
+ return m_bDirty;
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates the root element
+//-----------------------------------------------------------------------------
+bool CPetDoc::CreateRootElement()
+{
+ Assert( !m_hRoot.Get() );
+
+ DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( GetFileName() );
+
+ // Create the main element
+ m_hRoot = g_pDataModel->CreateElement( "DmElement", GetFileName(), fileid );
+ if ( m_hRoot == DMELEMENT_HANDLE_INVALID )
+ return false;
+
+ g_pDataModel->SetFileRoot( fileid, m_hRoot );
+
+ // We need to create an element array attribute storing particle system definitions
+ m_hRoot->AddAttribute( "particleSystemDefinitions", AT_ELEMENT_ARRAY );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates a new document
+//-----------------------------------------------------------------------------
+void CPetDoc::CreateNew()
+{
+ Assert( !m_hRoot.Get() );
+
+ // This is not undoable
+ CDisableUndoScopeGuard guard;
+
+ Q_strncpy( m_pFileName, "untitled", sizeof( m_pFileName ) );
+
+ // Create the main element
+ if ( !CreateRootElement() )
+ return;
+
+ SetDirty( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Saves/loads from file
+//-----------------------------------------------------------------------------
+bool CPetDoc::LoadFromFile( const char *pFileName )
+{
+ Assert( !m_hRoot.Get() );
+
+ CAppDisableUndoScopeGuard guard( "CPetDoc::LoadFromFile", NOTIFY_CHANGE_OTHER );
+ SetDirty( false );
+
+ if ( !pFileName[0] )
+ return false;
+
+ Q_strncpy( m_pFileName, pFileName, sizeof( m_pFileName ) );
+
+ CDmElement *pRoot = NULL;
+ DmFileId_t fileid = g_pDataModel->RestoreFromFile( pFileName, NULL, NULL, &pRoot, CR_DELETE_OLD );
+
+ if ( fileid == DMFILEID_INVALID )
+ {
+ m_pFileName[0] = 0;
+ return false;
+ }
+
+ m_hRoot = pRoot;
+
+ SetDirty( false );
+ return true;
+}
+
+void CPetDoc::SaveToFile( )
+{
+ if ( m_hRoot.Get() && m_pFileName && m_pFileName[0] )
+ {
+ g_pDataModel->SaveToFile( m_pFileName, NULL, "binary", PET_FILE_FORMAT, m_hRoot );
+ }
+
+ SetDirty( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the root object
+//-----------------------------------------------------------------------------
+CDmElement *CPetDoc::GetRootObject()
+{
+ return m_hRoot;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the root object fileid
+//-----------------------------------------------------------------------------
+DmFileId_t CPetDoc::GetFileId()
+{
+ return m_hRoot.Get() ? m_hRoot->GetFileId() : DMFILEID_INVALID;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the particle system definition list
+//-----------------------------------------------------------------------------
+CDmAttribute *CPetDoc::GetParticleSystemDefinitionList()
+{
+ CDmrElementArray<> array( m_hRoot, "particleSystemDefinitions" );
+ return array.GetAttribute();
+}
+
+
+void CPetDoc::AddNewParticleSystemDefinition( CDmeParticleSystemDefinition *pNew, CUndoScopeGuard &Guard )
+{
+ CDmrParticleSystemList particleSystemList( GetParticleSystemDefinitionList() );
+
+ particleSystemList.AddToTail( pNew );
+ Guard.Release();
+
+ // Force a resolve to get the particle created
+ g_pDmElementFramework->Operate( true );
+ g_pDmElementFramework->BeginEdit();
+
+ UpdateParticleDefinition( pNew );
+}
+
+//-----------------------------------------------------------------------------
+// Adds a new particle system definition
+//-----------------------------------------------------------------------------
+CDmeParticleSystemDefinition* CPetDoc::AddNewParticleSystemDefinition( const char *pName )
+{
+ if ( !pName || !pName[0] )
+ {
+ pName = "New Particle System";
+ }
+
+ CDmeParticleSystemDefinition *pParticleSystem;
+ {
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Add Particle System", "Add Particle System" );
+
+ pParticleSystem = CreateElement<CDmeParticleSystemDefinition>( pName, GetFileId() );
+ AddNewParticleSystemDefinition( pParticleSystem, guard );
+ }
+
+ return pParticleSystem;
+}
+
+
+//-----------------------------------------------------------------------------
+// Refresh all particle definitions
+//-----------------------------------------------------------------------------
+void CPetDoc::UpdateAllParticleSystems( )
+{
+ // Force a resolve to get the particle created
+ g_pDmElementFramework->Operate( true );
+ g_pDmElementFramework->BeginEdit();
+
+ CDmrParticleSystemList particleSystemList( GetParticleSystemDefinitionList() );
+ int nCount = particleSystemList.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ UpdateParticleDefinition( particleSystemList[i] );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Deletes a particle system definition
+//-----------------------------------------------------------------------------
+void CPetDoc::DeleteParticleSystemDefinition( CDmeParticleSystemDefinition *pParticleSystem )
+{
+ if ( !pParticleSystem )
+ return;
+
+ CDmrParticleSystemList particleSystemList( GetParticleSystemDefinitionList() );
+ int nCount = particleSystemList.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ if ( pParticleSystem == particleSystemList[i] )
+ {
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Delete Particle System", "Delete Particle System" );
+ particleSystemList.FastRemove( i );
+ break;
+ }
+ }
+
+ // Find all CDmeParticleChilds referring to this function
+ CUtlVector< CDmeParticleChild* > children;
+ FindAncestorsReferencingElement( pParticleSystem, children );
+ int nChildCount = children.Count();
+ for ( int i = 0; i < nChildCount; ++i )
+ {
+ CDmeParticleChild *pChildReference = children[i];
+ CDmeParticleSystemDefinition *pParent = FindReferringElement<CDmeParticleSystemDefinition>( pChildReference, "children" );
+ if ( !pParent )
+ continue;
+
+ pParent->RemoveFunction( FUNCTION_CHILDREN, pChildReference );
+ DestroyElement( pChildReference, TD_NONE );
+ }
+
+ DestroyElement( pParticleSystem, TD_DEEP );
+}
+
+
+CDmeParticleSystemDefinition *CPetDoc::FindParticleSystemDefinition( const char *pName )
+{
+ CDmrParticleSystemList particleSystemList( GetParticleSystemDefinitionList() );
+ int nCount = particleSystemList.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeParticleSystemDefinition* pParticleSystem = particleSystemList[i];
+ if ( !Q_stricmp( pName, pParticleSystem->GetName() ) )
+ return pParticleSystem;
+ }
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Deletes a particle system definition
+//-----------------------------------------------------------------------------
+void CPetDoc::ReplaceParticleSystemDefinition( CDmeParticleSystemDefinition *pParticleSystem )
+{
+ if ( !pParticleSystem )
+ return;
+
+ CDmrParticleSystemList particleSystemList( GetParticleSystemDefinitionList() );
+ int nCount = particleSystemList.Count();
+ int nFoundIndex = -1;
+ for ( int i = 0; i < nCount; ++i )
+ {
+ if ( !particleSystemList[i] )
+ continue;
+
+ if ( !Q_stricmp( particleSystemList[i]->GetName(), pParticleSystem->GetName() ) )
+ {
+ nFoundIndex = i;
+ break;
+ }
+ }
+
+ if ( nFoundIndex < 0 )
+ {
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Replace Particle System", "Replace Particle System" );
+ CDmrParticleSystemList particleSystemList( GetParticleSystemDefinitionList() );
+ pParticleSystem->SetFileId( m_hRoot->GetFileId(), TD_ALL );
+ particleSystemList.AddToTail( pParticleSystem );
+ return;
+ }
+
+ CDmeParticleSystemDefinition *pOldParticleSystem = particleSystemList[nFoundIndex];
+
+ // This can happen if we unserialized w/ replace
+ if ( pOldParticleSystem == pParticleSystem )
+ return;
+
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Replace Particle System", "Replace Particle System" );
+
+ particleSystemList.Set( nFoundIndex, pParticleSystem );
+ pParticleSystem->SetFileId( m_hRoot->GetFileId(), TD_ALL );
+
+ // Find all CDmeParticleChilds referring to this function
+ CUtlVector< CDmeParticleChild* > children;
+ FindAncestorsReferencingElement( pOldParticleSystem, children );
+ int nChildCount = children.Count();
+ for ( int i = 0; i < nChildCount; ++i )
+ {
+ CDmeParticleChild *pChildReference = children[i];
+ pChildReference->m_Child = pParticleSystem;
+ }
+
+ DestroyElement( pOldParticleSystem, TD_SHALLOW );
+}
+
+
+//-----------------------------------------------------------------------------
+// Does a particle system exist already?
+//-----------------------------------------------------------------------------
+bool CPetDoc::IsParticleSystemDefined( const char *pName )
+{
+ return FindParticleSystemDefinition( pName ) != NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Updates a specific particle defintion
+//-----------------------------------------------------------------------------
+void CPetDoc::UpdateParticleDefinition( CDmeParticleSystemDefinition *pDef )
+{
+ if ( !pDef )
+ return;
+
+ CUtlBuffer buf;
+ g_pDataModel->Serialize( buf, "binary", PET_FILE_FORMAT, pDef->GetHandle() );
+
+ // Tell the game about the new definitions
+ if ( clienttools )
+ {
+ clienttools->ReloadParticleDefintions( GetFileName(), buf.Base(), buf.TellMaxPut() );
+ }
+ if ( servertools )
+ {
+ servertools->ReloadParticleDefintions( GetFileName(), buf.Base(), buf.TellMaxPut() );
+ }
+
+ // Let the other tools know
+ KeyValues *pMessage = new KeyValues( "ParticleSystemUpdated" );
+ pMessage->SetPtr( "definitionBits", buf.Base() );
+ pMessage->SetInt( "definitionSize", buf.TellMaxPut() );
+ g_pPetTool->PostMessageToAllTools( pMessage );
+ pMessage->deleteThis();
+}
+
+
+//-----------------------------------------------------------------------------
+// Populate string choice lists
+//-----------------------------------------------------------------------------
+bool CPetDoc::GetStringChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, StringChoiceList_t &list )
+{
+ if ( !Q_stricmp( pChoiceListType, "particleSystemDefinitions" ) )
+ {
+ CDmrParticleSystemList particleSystemList( GetParticleSystemDefinitionList() );
+
+ StringChoice_t sChoice;
+ sChoice.m_pValue = "";
+ sChoice.m_pChoiceString = "";
+ list.AddToTail( sChoice );
+
+ int nCount = particleSystemList.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeParticleSystemDefinition *pParticleSystem = particleSystemList[ i ];
+
+ StringChoice_t sChoice;
+ sChoice.m_pValue = pParticleSystem->GetName();
+ sChoice.m_pChoiceString = pParticleSystem->GetName();
+ list.AddToTail( sChoice );
+ }
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Populate element choice lists
+//-----------------------------------------------------------------------------
+bool CPetDoc::GetElementChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, ElementChoiceList_t &list )
+{
+ if ( !Q_stricmp( pChoiceListType, "allelements" ) )
+ {
+ AddElementsRecursively( m_hRoot, list );
+ return true;
+ }
+
+ if ( !Q_stricmp( pChoiceListType, "particleSystemDefinitions" ) )
+ {
+ CDmrParticleSystemList particleSystemList( GetParticleSystemDefinitionList() );
+
+ int nCount = particleSystemList.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeParticleSystemDefinition *pParticleSystem = particleSystemList[ i ];
+ ElementChoice_t sChoice;
+ sChoice.m_pValue = pParticleSystem;
+ sChoice.m_pChoiceString = pParticleSystem->GetName();
+ list.AddToTail( sChoice );
+ }
+ return ( nCount > 0 );
+ }
+
+ // by default, try to treat the choice list type as a Dme element type
+ AddElementsRecursively( m_hRoot, list, pChoiceListType );
+
+ return list.Count() > 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when data changes
+//-----------------------------------------------------------------------------
+void CPetDoc::OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ SetDirty( nNotifyFlags & NOTIFY_SETDIRTYFLAG ? true : false );
+ m_pCallback->OnDocChanged( pReason, nNotifySource, nNotifyFlags );
+}
+
+
diff --git a/tools/pet/petdoc.h b/tools/pet/petdoc.h
new file mode 100644
index 0000000..d0f56c7
--- /dev/null
+++ b/tools/pet/petdoc.h
@@ -0,0 +1,122 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef PETDOC_H
+#define PETDOC_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "dme_controls/inotifyui.h"
+#include "datamodel/dmehandle.h"
+#include "datamodel/dmelement.h"
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class IPetDocCallback;
+class CPetDoc;
+class CDmeParticleSystemDefinition;
+
+
+//-----------------------------------------------------------------------------
+// The file format for particle system definitions
+//-----------------------------------------------------------------------------
+#define PET_FILE_FORMAT "pcf"
+
+
+typedef CDmrElementArray<CDmeParticleSystemDefinition> CDmrParticleSystemList;
+
+
+//-----------------------------------------------------------------------------
+// Contains all editable state
+//-----------------------------------------------------------------------------
+class CPetDoc : public IDmNotify, CBaseElementPropertiesChoices
+{
+public:
+ CPetDoc( IPetDocCallback *pCallback );
+ ~CPetDoc();
+
+ // Inherited from INotifyUI
+ virtual void NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+ virtual bool GetIntChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, IntChoiceList_t &list );
+
+ // Sets/Gets the file name
+ const char *GetFileName();
+ void SetFileName( const char *pFileName );
+
+ // Dirty bits (has it changed since the last time it was saved?)
+ void SetDirty( bool bDirty );
+ bool IsDirty() const;
+
+ // Creates a new document
+ void CreateNew();
+
+ // Saves/loads from file
+ bool LoadFromFile( const char *pFileName );
+ void SaveToFile( );
+
+ // Returns the root object
+ CDmElement *GetRootObject();
+
+ // Returns the root object fileid
+ DmFileId_t GetFileId();
+
+ // Called when data changes (see INotifyUI for flags)
+ void OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Returns the particle system definition list
+ CDmAttribute *GetParticleSystemDefinitionList();
+
+ // add a new definition we've created
+ void AddNewParticleSystemDefinition( CDmeParticleSystemDefinition *pNew,
+ CUndoScopeGuard &Guard );
+
+ // Adds a new particle system definition
+ CDmeParticleSystemDefinition *AddNewParticleSystemDefinition( const char *pName );
+
+ // Deletes a particle system definition
+ void DeleteParticleSystemDefinition( CDmeParticleSystemDefinition *pParticleSystem );
+
+ // find particle system def by name
+ CDmeParticleSystemDefinition *FindParticleSystemDefinition( const char *pName );
+
+ // Replace any particle system with the same name as the passed-in definition
+ // with the passed-in definition
+ void ReplaceParticleSystemDefinition( CDmeParticleSystemDefinition *pParticleSystem );
+
+ // Does a particle system exist already?
+ bool IsParticleSystemDefined( const char *pName );
+
+ // For element choice lists. Return false if it's an unknown choice list type
+ virtual bool GetStringChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, StringChoiceList_t &list );
+ virtual bool GetElementChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, ElementChoiceList_t &list );
+
+ // Updates a specific particle defintion
+ void UpdateParticleDefinition( CDmeParticleSystemDefinition *pDef );
+
+ // Update all particle definitions
+ void UpdateAllParticleSystems( );
+
+private:
+ // Creates the root element
+ bool CreateRootElement();
+
+ IPetDocCallback *m_pCallback;
+ CDmeHandle< CDmElement > m_hRoot;
+ char m_pFileName[MAX_PATH];
+ bool m_bDirty;
+};
+
+
+#endif // PETDOC_H
diff --git a/tools/pet/pettool.cpp b/tools/pet/pettool.cpp
new file mode 100644
index 0000000..2eb83e5
--- /dev/null
+++ b/tools/pet/pettool.cpp
@@ -0,0 +1,1078 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core Movie Maker UI API
+//
+//=============================================================================
+
+#include "pettool.h"
+#include "vgui_controls/Menu.h"
+#include "tier1/KeyValues.h"
+#include "vgui/IInput.h"
+#include "vgui/KeyCode.h"
+#include "vgui_controls/FileOpenDialog.h"
+#include "filesystem.h"
+#include "vgui/ilocalize.h"
+#include "dme_controls/elementpropertiestree.h"
+#include "tier0/icommandline.h"
+#include "materialsystem/imaterialsystem.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "petdoc.h"
+#include "particlesystemdefinitionbrowser.h"
+#include "particlesystempropertiescontainer.h"
+#include "dme_controls/AttributeStringChoicePanel.h"
+#include "dme_controls/ParticleSystemPanel.h"
+#include "datamodel/dmelementfactoryhelper.h"
+#include "matsys_controls/picker.h"
+#include "tier2/fileutils.h"
+#include "tier3/tier3.h"
+#include "particles/particles.h"
+#include "dmserializers/idmserializers.h"
+#include "dme_controls/dmepanel.h"
+#include "vgui/ivgui.h"
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Methods needed by scenedatabase. They have to live here instead of toolutils
+// because this is a DLL but toolutils is only a static library
+//-----------------------------------------------------------------------------
+USING_DMEPANEL_FACTORY( CParticleSystemPreviewPanel, DmeParticleSystemDefinition );
+USING_DMEPANEL_FACTORY( CParticleSystemDmePanel, DmeParticleSystemDefinition );
+
+
+const char *GetVGuiControlsModuleName()
+{
+ return "PetTool";
+}
+
+//-----------------------------------------------------------------------------
+// Connect, disconnect
+//-----------------------------------------------------------------------------
+bool ConnectTools( CreateInterfaceFn factory )
+{
+ // Attach to the dmserializers instance of the particle system
+ return (materials != NULL) && (g_pMatSystemSurface != NULL) && (g_pMDLCache != NULL) && (studiorender != NULL) && (g_pMaterialSystemHardwareConfig != NULL);
+}
+
+void DisconnectTools( )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Singleton
+//-----------------------------------------------------------------------------
+CPetTool *g_pPetTool = NULL;
+
+void CreateTools()
+{
+ g_pPetTool = new CPetTool();
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CPetTool::CPetTool()
+{
+ m_pMenuBar = NULL;
+ m_pDoc = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Init, shutdown
+//-----------------------------------------------------------------------------
+bool CPetTool::Init( )
+{
+ m_hCurrentParticleSystem = NULL;
+ m_pDoc = NULL;
+ m_RecentFiles.LoadFromRegistry( GetRegistryName() );
+
+ // NOTE: This has to happen before BaseClass::Init
+ g_pVGuiLocalize->AddFile( "resource/toolpet_%language%.txt" );
+
+ if ( !BaseClass::Init( ) )
+ return false;
+
+ CreateInterfaceFn factory;
+ enginetools->GetClientFactory( factory );
+ IParticleSystemQuery *pQuery = (IParticleSystemQuery*)factory( PARTICLE_SYSTEM_QUERY_INTERFACE_VERSION, NULL );
+ g_pParticleSystemMgr->Init( pQuery );
+ // tell particle mgr to add the default simulation + rendering ops
+ g_pParticleSystemMgr->AddBuiltinSimulationOperators();
+ g_pParticleSystemMgr->AddBuiltinRenderingOperators();
+
+ // Create a directory for particles if it doesn't exist
+ char pStartingDir[ MAX_PATH ];
+ GetModSubdirectory( "particles", pStartingDir, sizeof(pStartingDir) );
+ g_pFullFileSystem->CreateDirHierarchy( pStartingDir );
+
+ return true;
+}
+
+void CPetTool::Shutdown()
+{
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+
+ BaseClass::Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// returns the document
+//-----------------------------------------------------------------------------
+CPetDoc *CPetTool::GetDocument()
+{
+ return m_pDoc;
+}
+
+
+//-----------------------------------------------------------------------------
+// Tool activation/deactivation
+//-----------------------------------------------------------------------------
+void CPetTool::OnToolActivate()
+{
+ BaseClass::OnToolActivate();
+}
+
+void CPetTool::OnToolDeactivate()
+{
+ BaseClass::OnToolDeactivate();
+}
+
+
+//-----------------------------------------------------------------------------
+// Used to hook DME VMF entities into the render lists
+//-----------------------------------------------------------------------------
+void CPetTool::Think( bool finalTick )
+{
+ BaseClass::Think( finalTick );
+
+ if ( IsActiveTool() )
+ {
+ // Force resolve calls to happen
+ // FIXME: Shouldn't this not have to happen here?
+ CUtlVector< IDmeOperator* > operators;
+ g_pDmElementFramework->SetOperators( operators );
+ g_pDmElementFramework->Operate( true );
+ g_pDmElementFramework->BeginEdit();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get a new scheme to be applied to this tool
+//-----------------------------------------------------------------------------
+vgui::HScheme CPetTool::GetToolScheme()
+{
+ return vgui::scheme()->LoadSchemeFromFile( "Resource/BoxRocket.res", "BoxRocket" );
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// The View menu
+//
+//-----------------------------------------------------------------------------
+class CPetViewMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CPetViewMenuButton, CToolMenuButton );
+public:
+ CPetViewMenuButton( CPetTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+
+private:
+ CPetTool *m_pTool;
+};
+
+CPetViewMenuButton::CPetViewMenuButton( CPetTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ m_pTool = parent;
+
+ AddCheckableMenuItem( "properties", "#PetProperties", new KeyValues( "OnToggleProperties" ), pActionSignalTarget );
+ AddCheckableMenuItem( "browser", "#PetParticleSystemBrowser", new KeyValues( "OnToggleParticleSystemBrowser" ), pActionSignalTarget );
+ AddCheckableMenuItem( "particlepreview", "#PetParticlePreview", new KeyValues( "OnToggleParticlePreview" ), pActionSignalTarget );
+
+ AddSeparator();
+
+ AddMenuItem( "defaultlayout", "#PetViewDefault", new KeyValues( "OnDefaultLayout" ), pActionSignalTarget );
+
+ SetMenu(m_pMenu);
+}
+
+void CPetViewMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ int id;
+
+ CPetDoc *pDoc = m_pTool->GetDocument();
+ if ( pDoc )
+ {
+ id = m_Items.Find( "properties" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ Panel *p;
+ p = m_pTool->GetProperties();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+
+ id = m_Items.Find( "browser" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ p = m_pTool->GetParticleSystemDefinitionBrowser();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+
+ id = m_Items.Find( "particlepreview" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ p = m_pTool->GetParticlePreview();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+ }
+ else
+ {
+ id = m_Items.Find( "properties" );
+ m_pMenu->SetItemEnabled( id, false );
+ id = m_Items.Find( "browser" );
+ m_pMenu->SetItemEnabled( id, false );
+ id = m_Items.Find( "particlepreview" );
+ m_pMenu->SetItemEnabled( id, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// The Tool menu
+//
+//-----------------------------------------------------------------------------
+class CPetToolMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CPetToolMenuButton, CToolMenuButton );
+public:
+ CPetToolMenuButton( CPetTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+
+private:
+ CPetTool *m_pTool;
+};
+
+CPetToolMenuButton::CPetToolMenuButton( CPetTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ m_pTool = parent;
+
+ SetMenu(m_pMenu);
+}
+
+void CPetToolMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the menu bar
+//-----------------------------------------------------------------------------
+vgui::MenuBar *CPetTool::CreateMenuBar( CBaseToolSystem *pParent )
+{
+ m_pMenuBar = new CToolFileMenuBar( pParent, "Main Menu Bar" );
+
+ // Sets info in the menu bar
+ char title[ 64 ];
+ ComputeMenuBarTitle( title, sizeof( title ) );
+ m_pMenuBar->SetInfo( title );
+ m_pMenuBar->SetToolName( GetToolName() );
+
+ // Add menu buttons
+ CToolMenuButton *pFileButton = CreateToolFileMenuButton( m_pMenuBar, "File", "&File", GetActionTarget(), this );
+ CToolMenuButton *pEditButton = CreateToolEditMenuButton( this, "Edit", "&Edit", GetActionTarget() );
+ CPetToolMenuButton *pToolButton = new CPetToolMenuButton( this, "Pet", "&Pet", GetActionTarget() );
+ CPetViewMenuButton *pViewButton = new CPetViewMenuButton( this, "View", "&View", GetActionTarget() );
+ CToolMenuButton *pSwitchButton = CreateToolSwitchMenuButton( m_pMenuBar, "Switcher", "&Tools", GetActionTarget() );
+
+ pEditButton->AddMenuItem( "copy", "#BxEditCopy", new KeyValues( "OnCopy" ), GetActionTarget(), NULL, "edit_copy" );
+ pEditButton->AddMenuItem( "paste", "#BxEditPaste", new KeyValues( "OnPaste" ), GetActionTarget(), NULL, "edit_paste" );
+
+ pEditButton->MoveMenuItem( pEditButton->FindMenuItem( "paste" ), pEditButton->FindMenuItem( "editkeybindings" ) );
+ pEditButton->MoveMenuItem( pEditButton->FindMenuItem( "copy" ), pEditButton->FindMenuItem( "paste" ) );
+ pEditButton->AddSeparatorAfterItem( "paste" );
+
+ m_pMenuBar->AddButton( pFileButton );
+ m_pMenuBar->AddButton( pEditButton );
+ m_pMenuBar->AddButton( pToolButton );
+ m_pMenuBar->AddButton( pViewButton );
+ m_pMenuBar->AddButton( pSwitchButton );
+
+ return m_pMenuBar;
+}
+
+
+//-----------------------------------------------------------------------------
+// Updates the menu bar based on the current file
+//-----------------------------------------------------------------------------
+void CPetTool::UpdateMenuBar( )
+{
+ if ( !m_pDoc )
+ {
+ m_pMenuBar->SetFileName( "#PetNoFile" );
+ return;
+ }
+
+ const char *pFile = m_pDoc->GetFileName();
+ if ( !pFile[0] )
+ {
+ m_pMenuBar->SetFileName( "#PetNoFile" );
+ return;
+ }
+
+ if ( m_pDoc->IsDirty() )
+ {
+ char sz[ 512 ];
+ Q_snprintf( sz, sizeof( sz ), "* %s", pFile );
+ m_pMenuBar->SetFileName( sz );
+ }
+ else
+ {
+ m_pMenuBar->SetFileName( pFile );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets at tool windows
+//-----------------------------------------------------------------------------
+CParticleSystemPropertiesContainer *CPetTool::GetProperties()
+{
+ return m_hProperties.Get();
+}
+
+CParticleSystemDefinitionBrowser *CPetTool::GetParticleSystemDefinitionBrowser()
+{
+ return m_hParticleSystemDefinitionBrowser.Get();
+}
+
+CParticleSystemPreviewPanel *CPetTool::GetParticlePreview()
+{
+ return m_hParticlePreview.Get();
+}
+
+
+//-----------------------------------------------------------------------------
+// Copy/paste
+//-----------------------------------------------------------------------------
+void CPetTool::OnCopy()
+{
+ GetParticleSystemDefinitionBrowser()->CopyToClipboard();
+}
+
+void CPetTool::OnPaste()
+{
+ GetParticleSystemDefinitionBrowser()->PasteFromClipboard();
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets/gets the current particle system
+//-----------------------------------------------------------------------------
+void CPetTool::SetCurrentParticleSystem( CDmeParticleSystemDefinition *pParticleSystem, bool bForceBrowserSelection )
+{
+ if ( !m_pDoc )
+ return;
+
+ if ( m_hCurrentParticleSystem.Get() == pParticleSystem )
+ return;
+
+ m_hCurrentParticleSystem = pParticleSystem;
+ if ( bForceBrowserSelection && m_hParticleSystemDefinitionBrowser.Get() )
+ {
+ m_hParticleSystemDefinitionBrowser->UpdateParticleSystemList();
+ m_hParticleSystemDefinitionBrowser->SelectParticleSystem( pParticleSystem );
+ }
+ if ( m_hParticlePreview.Get() )
+ {
+ m_hParticlePreview->SetParticleSystem( pParticleSystem );
+ }
+ if ( m_hProperties.Get() )
+ {
+ m_hProperties->SetParticleSystem( m_hCurrentParticleSystem );
+ }
+}
+
+CDmeParticleSystemDefinition* CPetTool::GetCurrentParticleSystem( void )
+{
+ return m_hCurrentParticleSystem;
+}
+
+
+//-----------------------------------------------------------------------------
+// Destroys all tool windows
+//-----------------------------------------------------------------------------
+void CPetTool::DestroyToolContainers()
+{
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets up the default layout
+//-----------------------------------------------------------------------------
+void CPetTool::OnDefaultLayout()
+{
+ int y = m_pMenuBar->GetTall();
+
+ int usew, useh;
+ GetSize( usew, useh );
+
+ DestroyToolContainers();
+
+ Assert( ToolWindow::GetToolWindowCount() == 0 );
+
+ CParticleSystemPropertiesContainer *pProperties = GetProperties();
+ CParticleSystemDefinitionBrowser *pParticleSystemBrowser = GetParticleSystemDefinitionBrowser();
+ CParticleSystemPreviewPanel *pPreviewer = GetParticlePreview();
+
+ // Need three containers
+ ToolWindow *pPropertyWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, pProperties, "#PetProperties", false );
+ ToolWindow *pBrowserWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, pParticleSystemBrowser, "#PetParticleSystemBrowser", false );
+ ToolWindow *pPreviewWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, pPreviewer, "#PetPreviewer", false );
+
+ int halfScreen = usew / 2;
+ int bottom = useh - y;
+ int sy = (bottom - y) / 2;
+ SetMiniViewportBounds( halfScreen, y, halfScreen, sy - y );
+ pPreviewWindow->SetBounds( halfScreen, sy, halfScreen, bottom - sy );
+ pBrowserWindow->SetBounds( 0, y, halfScreen, sy - y );
+ pPropertyWindow->SetBounds( 0, sy, halfScreen, bottom - sy );
+}
+
+void CPetTool::OnToggleProperties()
+{
+ if ( m_hProperties.Get() )
+ {
+ ToggleToolWindow( m_hProperties.Get(), "#PetProperties" );
+ }
+}
+
+void CPetTool::OnToggleParticleSystemBrowser()
+{
+ if ( m_hParticleSystemDefinitionBrowser.Get() )
+ {
+ ToggleToolWindow( m_hParticleSystemDefinitionBrowser.Get(), "#PetParticleSystemBrowser" );
+ }
+}
+
+void CPetTool::OnToggleParticlePreview()
+{
+ if ( m_hParticlePreview.Get() )
+ {
+ ToggleToolWindow( m_hParticlePreview.Get(), "#PetPreviewer" );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates
+//-----------------------------------------------------------------------------
+void CPetTool::CreateTools( CPetDoc *doc )
+{
+ if ( !m_hProperties.Get() )
+ {
+ m_hProperties = new CParticleSystemPropertiesContainer( m_pDoc, this );
+ }
+
+ if ( !m_hParticleSystemDefinitionBrowser.Get() )
+ {
+ m_hParticleSystemDefinitionBrowser = new CParticleSystemDefinitionBrowser( m_pDoc, this, "ParticleSystemDefinitionBrowser" );
+ }
+
+ if ( !m_hParticlePreview.Get() )
+ {
+ m_hParticlePreview = new CParticleSystemPreviewPanel( NULL, "Particle System Preview" );
+ }
+ RegisterToolWindow( m_hProperties );
+ RegisterToolWindow( m_hParticleSystemDefinitionBrowser );
+ RegisterToolWindow( m_hParticlePreview );
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the tools
+//-----------------------------------------------------------------------------
+void CPetTool::InitTools()
+{
+ // FIXME: There are no tool windows here; how should this work?
+ // These panels are saved
+ windowposmgr->RegisterPanel( "properties", m_hProperties, false );
+ windowposmgr->RegisterPanel( "particlesystemdefinitionbrowser", m_hParticleSystemDefinitionBrowser, false );
+ windowposmgr->RegisterPanel( "previewpanel", m_hParticlePreview, false );
+
+ if ( !windowposmgr->LoadPositions( "cfg/pet.txt", this, &m_ToolWindowFactory, "Pet" ) )
+ {
+ OnDefaultLayout();
+ }
+}
+
+
+void CPetTool::DestroyTools()
+{
+ SetCurrentParticleSystem( NULL );
+
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+
+ UnregisterAllToolWindows();
+
+ if ( m_hProperties.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hProperties.Get() );
+ delete m_hProperties.Get();
+ m_hProperties = NULL;
+ }
+
+ if ( m_hParticleSystemDefinitionBrowser.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hParticleSystemDefinitionBrowser.Get() );
+ delete m_hParticleSystemDefinitionBrowser.Get();
+ m_hParticleSystemDefinitionBrowser = NULL;
+ }
+
+ if ( m_hParticlePreview.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hParticlePreview.Get() );
+ delete m_hParticlePreview.Get();
+ m_hParticlePreview = NULL;
+ }
+}
+
+
+void CPetTool::ShowToolWindow( Panel *tool, char const *toolName, bool visible )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL && visible )
+ {
+ m_ToolWindowFactory.InstanceToolWindow( this, false, tool, toolName, false );
+ }
+ else if ( !visible )
+ {
+ ToolWindow *tw = dynamic_cast< ToolWindow * >( tool->GetParent()->GetParent() );
+ Assert( tw );
+ tw->RemovePage( tool );
+ }
+}
+
+void CPetTool::ToggleToolWindow( Panel *tool, char const *toolName )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL )
+ {
+ ShowToolWindow( tool, toolName, true );
+ }
+ else
+ {
+ ShowToolWindow( tool, toolName, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates the action menu
+//-----------------------------------------------------------------------------
+vgui::Menu *CPetTool::CreateActionMenu( vgui::Panel *pParent )
+{
+ vgui::Menu *pActionMenu = new Menu( pParent, "ActionMenu" );
+ pActionMenu->AddMenuItem( "#ToolHide", new KeyValues( "Command", "command", "HideActionMenu" ), GetActionTarget() );
+ return pActionMenu;
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from IFileMenuCallbacks
+//-----------------------------------------------------------------------------
+int CPetTool::GetFileMenuItemsEnabled( )
+{
+ int nFlags = FILE_ALL;
+ if ( m_RecentFiles.IsEmpty() )
+ {
+ nFlags &= ~(FILE_RECENT | FILE_CLEAR_RECENT);
+ }
+ return nFlags;
+}
+
+void CPetTool::AddRecentFilesToMenu( vgui::Menu *pMenu )
+{
+ m_RecentFiles.AddToMenu( pMenu, GetActionTarget(), "OnRecent" );
+}
+
+bool CPetTool::GetPerforceFileName( char *pFileName, int nMaxLen )
+{
+ if ( !m_pDoc )
+ return false;
+
+ Q_strncpy( pFileName, m_pDoc->GetFileName(), nMaxLen );
+ return pFileName[0] != 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+void CPetTool::OnExit()
+{
+ windowposmgr->SavePositions( "cfg/pet.txt", "Pet" );
+
+ enginetools->Command( "quit\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Handle commands from the action menu and other menus
+//-----------------------------------------------------------------------------
+void CPetTool::OnCommand( const char *cmd )
+{
+ if ( !V_stricmp( cmd, "HideActionMenu" ) )
+ {
+ if ( GetActionMenu() )
+ {
+ GetActionMenu()->SetVisible( false );
+ }
+ }
+ else if ( const char *pSuffix = StringAfterPrefix( cmd, "OnRecent" ) )
+ {
+ int idx = Q_atoi( pSuffix );
+ OpenFileFromHistory( idx );
+ }
+ else if ( const char *pSuffix = StringAfterPrefix( cmd, "OnTool" ) )
+ {
+ int idx = Q_atoi( pSuffix );
+ enginetools->SwitchToTool( idx );
+ }
+ else if ( !V_stricmp( cmd, "OnUndo" ) )
+ {
+ OnUndo();
+ }
+ else if ( !V_stricmp( cmd, "OnRedo" ) )
+ {
+ OnRedo();
+ }
+ else if ( !V_stricmp( cmd, "OnDescribeUndo" ) )
+ {
+ OnDescribeUndo();
+ }
+ else
+ {
+ BaseClass::OnCommand( cmd );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Command handlers
+//-----------------------------------------------------------------------------
+void CPetTool::PerformNew()
+{
+ OnCloseNoSave();
+ NewDocument();
+}
+
+void CPetTool::OnNew()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetFileName(), PET_FILE_FORMAT, FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnNew" ) );
+ return;
+ }
+
+ PerformNew();
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when the File->Open menu is selected
+//-----------------------------------------------------------------------------
+void CPetTool::OnOpen( )
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetFileName();
+ }
+
+ OpenFile( PET_FILE_FORMAT, pSaveFileName, PET_FILE_FORMAT, nFlags );
+}
+
+bool CPetTool::OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ OnCloseNoSave();
+
+ if ( !LoadDocument( pFileName ) )
+ return false;
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ UpdateMenuBar();
+ return true;
+}
+
+void CPetTool::Save()
+{
+ if ( m_pDoc )
+ {
+ SaveFile( m_pDoc->GetFileName(), PET_FILE_FORMAT, FOSM_SHOW_PERFORCE_DIALOGS );
+ }
+}
+
+void CPetTool::OnSaveAs()
+{
+ if ( m_pDoc )
+ {
+ SaveFile( NULL, PET_FILE_FORMAT, FOSM_SHOW_PERFORCE_DIALOGS );
+ }
+}
+
+void CPetTool::OnRestartLevel()
+{
+ enginetools->Command( "restart" );
+ enginetools->Execute();
+}
+
+void CPetTool::SaveAndTest()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetFileName(), PET_FILE_FORMAT, FOSM_SHOW_PERFORCE_DIALOGS,
+ new KeyValues( "RestartLevel" ) );
+ }
+ else
+ {
+ OnRestartLevel();
+ }
+}
+
+bool CPetTool::OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ if ( !m_pDoc )
+ return true;
+
+ m_pDoc->SetFileName( pFileName );
+ m_pDoc->SaveToFile( );
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ UpdateMenuBar();
+ return true;
+}
+
+void CPetTool::OnClose()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetFileName(), PET_FILE_FORMAT, FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnClose" ) );
+ return;
+ }
+
+ OnCloseNoSave();
+}
+
+void CPetTool::OnCloseNoSave()
+{
+ DestroyTools();
+
+ if ( m_pDoc )
+ {
+ CAppNotifyScopeGuard sg( "CPetTool::OnCloseNoSave", NOTIFY_CHANGE_OTHER );
+
+ delete m_pDoc;
+ m_pDoc = NULL;
+
+ if ( m_hProperties )
+ {
+ m_hProperties->SetParticleSystem( NULL );
+ }
+ }
+
+ UpdateMenuBar( );
+}
+
+void CPetTool::OnMarkNotDirty()
+{
+ if ( m_pDoc )
+ {
+ m_pDoc->SetDirty( false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Open a specific file
+//-----------------------------------------------------------------------------
+void CPetTool::OpenSpecificFile( const char *pFileName )
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc )
+ {
+ // File is already open
+ if ( !Q_stricmp( m_pDoc->GetFileName(), pFileName ) )
+ return;
+
+ if ( m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetFileName();
+ }
+ else
+ {
+ OnCloseNoSave();
+ }
+ }
+
+ OpenFile( pFileName, PET_FILE_FORMAT, pSaveFileName, PET_FILE_FORMAT, nFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the save document query dialog
+//-----------------------------------------------------------------------------
+void CPetTool::OpenFileFromHistory( int slot )
+{
+ const char *pFileName = m_RecentFiles.GetFile( slot );
+ if ( !pFileName )
+ return;
+ OpenSpecificFile( pFileName );
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get notified when files are saved/loaded
+//-----------------------------------------------------------------------------
+void CPetTool::OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues )
+{
+ if ( bWroteFile )
+ {
+ OnMarkNotDirty();
+ }
+
+ if ( !pContextKeyValues )
+ return;
+
+ if ( state != FileOpenStateMachine::SUCCESSFUL )
+ return;
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnNew" ) )
+ {
+ PerformNew();
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnClose" ) )
+ {
+ OnCloseNoSave();
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnQuit" ) )
+ {
+ OnCloseNoSave();
+ vgui::ivgui()->PostMessage( GetVPanel(), new KeyValues( "OnExit" ), 0 );
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "RestartLevel" ) )
+ {
+ OnRestartLevel();
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the File browser dialog
+//-----------------------------------------------------------------------------
+void CPetTool::SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ char pStartingDir[ MAX_PATH ];
+
+ GetModSubdirectory( "particles", pStartingDir, sizeof(pStartingDir) );
+
+ // Open a bsp file to create a new commentary file
+ pDialog->SetTitle( "Choose Particle Configuration File", true );
+ pDialog->SetStartDirectoryContext( "pet_session", pStartingDir );
+ pDialog->AddFilter( "*.pcf", "Particle Configuration File (*.pcf)", true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Can we quit?
+//-----------------------------------------------------------------------------
+bool CPetTool::CanQuit()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ // Show Save changes Yes/No/Cancel and re-quit if hit yes/no
+ SaveFile( m_pDoc->GetFileName(), PET_FILE_FORMAT, FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnQuit" ) );
+ return false;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Various command handlers related to the Edit menu
+//-----------------------------------------------------------------------------
+void CPetTool::OnUndo()
+{
+ CDisableUndoScopeGuard guard;
+ g_pDataModel->Undo();
+}
+
+void CPetTool::OnRedo()
+{
+ CDisableUndoScopeGuard guard;
+ g_pDataModel->Redo();
+}
+
+void CPetTool::OnDescribeUndo()
+{
+ CUtlVector< UndoInfo_t > list;
+ g_pDataModel->GetUndoInfo( list );
+
+ Msg( "%i operations in stack\n", list.Count() );
+
+ for ( int i = list.Count() - 1; i >= 0; --i )
+ {
+ UndoInfo_t& entry = list[ i ];
+ if ( entry.terminator )
+ {
+ Msg( "[ '%s' ] - %i operations\n", entry.undo, entry.numoperations );
+ }
+
+ Msg( " +%s\n", entry.desc );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Background
+//-----------------------------------------------------------------------------
+const char *CPetTool::GetLogoTextureName()
+{
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from IPetDocCallback
+//-----------------------------------------------------------------------------
+void CPetTool::OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ CDmeParticleSystemDefinition *pParticleSystem = GetCurrentParticleSystem();
+ if ( m_pDoc && GetParticlePreview() && pParticleSystem )
+ {
+ m_pDoc->UpdateParticleDefinition( pParticleSystem );
+ }
+
+ if ( nNotifyFlags & NOTIFY_CHANGE_TOPOLOGICAL )
+ {
+ if ( GetParticleSystemDefinitionBrowser() )
+ {
+ GetParticleSystemDefinitionBrowser()->UpdateParticleSystemList();
+ }
+ }
+
+ bool bRefreshProperties = ( nNotifySource != NOTIFY_SOURCE_PROPERTIES_TREE ) &&
+ ( ( nNotifyFlags & ( NOTIFY_CHANGE_TOPOLOGICAL | NOTIFY_CHANGE_ATTRIBUTE_ARRAY_SIZE ) ) != 0 );
+ bool bRefreshPropertyValues = ( nNotifySource != NOTIFY_SOURCE_PROPERTIES_TREE ) &&
+ ( nNotifyFlags & NOTIFY_CHANGE_ATTRIBUTE_VALUE ) != 0;
+
+ if ( bRefreshProperties || bRefreshPropertyValues )
+ {
+ if ( m_hProperties.Get() )
+ {
+ m_hProperties->Refresh( !bRefreshProperties );
+ }
+ }
+
+ UpdateMenuBar();
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates a new document
+//-----------------------------------------------------------------------------
+void CPetTool::NewDocument( )
+{
+ Assert( !m_pDoc );
+
+ DestroyTools();
+
+ m_pDoc = new CPetDoc( this );
+ m_pDoc->CreateNew( );
+
+ ShowMiniViewport( true );
+ CreateTools( m_pDoc );
+ UpdateMenuBar( );
+ InitTools();
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads up a new document
+//-----------------------------------------------------------------------------
+bool CPetTool::LoadDocument( const char *pDocName )
+{
+ Assert( !m_pDoc );
+
+ DestroyTools();
+
+ m_pDoc = new CPetDoc( this );
+ if ( !m_pDoc->LoadFromFile( pDocName ) )
+ {
+ delete m_pDoc;
+ m_pDoc = NULL;
+ Warning( "Fatal error loading '%s'\n", pDocName );
+ return false;
+ }
+
+ ShowMiniViewport( true );
+
+ CreateTools( m_pDoc );
+ UpdateMenuBar( );
+ InitTools();
+
+ // Let the other tools know we've loaded + therefore modified particle systems
+ CUtlBuffer buf;
+ g_pDataModel->Serialize( buf, "binary", PET_FILE_FORMAT, m_pDoc->GetRootObject()->GetHandle() );
+
+ KeyValues *pMessage = new KeyValues( "ParticleSystemUpdated" );
+ pMessage->SetPtr( "definitionBits", buf.Base() );
+ pMessage->SetInt( "definitionSize", buf.TellMaxPut() );
+ PostMessageToAllTools( pMessage );
+ pMessage->deleteThis();
+ return true;
+}
+
+
diff --git a/tools/pet/pettool.h b/tools/pet/pettool.h
new file mode 100644
index 0000000..ba6395e
--- /dev/null
+++ b/tools/pet/pettool.h
@@ -0,0 +1,209 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: P.E.T. (Particle Editing Tool); main UI smarts class
+//
+//=============================================================================
+
+#ifndef PETTOOL_H
+#define PETTOOL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/platform.h"
+#include "toolutils/basetoolsystem.h"
+#include "toolutils/recentfilelist.h"
+#include "toolutils/toolmenubar.h"
+#include "toolutils/toolswitchmenubutton.h"
+#include "toolutils/tooleditmenubutton.h"
+#include "toolutils/toolfilemenubutton.h"
+#include "toolutils/toolmenubutton.h"
+#include "datamodel/dmelement.h"
+#include "datamodel/dmehandle.h"
+#include "toolframework/ienginetool.h"
+#include "toolutils/enginetools_int.h"
+#include "toolutils/savewindowpositions.h"
+#include "toolutils/toolwindowfactory.h"
+#include "movieobjects/dmeparticlesystemdefinition.h"
+#include "particles/particles.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CDmElement;
+class CPetDoc;
+class CParticleSystemPropertiesContainer;
+class CParticleSystemDefinitionBrowser;
+class CParticleSystemPreviewPanel;
+class CDmeParticleSystemDefinition;
+enum ParticleFunctionType_t;
+
+namespace vgui
+{
+ class Panel;
+}
+
+
+//-----------------------------------------------------------------------------
+// Allows the doc to call back into the CommEdit editor tool
+//-----------------------------------------------------------------------------
+abstract_class IPetDocCallback
+{
+public:
+ // Called by the doc when the data changes
+ virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags ) = 0;
+};
+
+
+//-----------------------------------------------------------------------------
+// Global methods of the commedit tool
+//-----------------------------------------------------------------------------
+abstract_class IPetTool
+{
+public:
+ // Gets at the rool panel (for modal dialogs)
+ virtual vgui::Panel *GetRootPanel() = 0;
+
+ // Gets the registry name (for saving settings)
+ virtual const char *GetRegistryName() = 0;
+};
+
+//-----------------------------------------------------------------------------
+// Implementation of the CommEdit tool
+//-----------------------------------------------------------------------------
+class CPetTool : public CBaseToolSystem, public IFileMenuCallbacks, public IPetDocCallback, public IPetTool
+{
+ DECLARE_CLASS_SIMPLE( CPetTool, CBaseToolSystem );
+
+public:
+ CPetTool();
+
+ // Inherited from IToolSystem
+ virtual const char *GetToolName() { return "Particle Editor"; }
+ virtual bool Init( );
+ virtual void Shutdown();
+ virtual bool CanQuit();
+ virtual void OnToolActivate();
+ virtual void OnToolDeactivate();
+ virtual void Think( bool finalTick );
+
+ // Inherited from IFileMenuCallbacks
+ virtual int GetFileMenuItemsEnabled( );
+ virtual void AddRecentFilesToMenu( vgui::Menu *menu );
+ virtual bool GetPerforceFileName( char *pFileName, int nMaxLen );
+
+ // Inherited from IPetDocCallback
+ virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+ virtual vgui::Panel *GetRootPanel() { return this; }
+
+ // Inherited from CBaseToolSystem
+ virtual vgui::HScheme GetToolScheme();
+ virtual vgui::Menu *CreateActionMenu( vgui::Panel *pParent );
+ virtual void OnCommand( const char *cmd );
+ virtual const char *GetRegistryName() { return "PetTool"; }
+ virtual const char *GetBindingsContextFile() { return "cfg/Pet.kb"; }
+ virtual vgui::MenuBar *CreateMenuBar( CBaseToolSystem *pParent );
+
+ MESSAGE_FUNC( Save, "OnSave" );
+ void SaveAndTest();
+
+public:
+ MESSAGE_FUNC( OnRestartLevel, "RestartLevel" );
+ MESSAGE_FUNC( OnNew, "OnNew" );
+ MESSAGE_FUNC( OnOpen, "OnOpen" );
+ MESSAGE_FUNC( OnSaveAs, "OnSaveAs" );
+ MESSAGE_FUNC( OnClose, "OnClose" );
+ MESSAGE_FUNC( OnCloseNoSave, "OnCloseNoSave" );
+ MESSAGE_FUNC( OnMarkNotDirty, "OnMarkNotDirty" );
+ MESSAGE_FUNC( OnExit, "OnExit" );
+ MESSAGE_FUNC( OnCopy, "OnCopy" );
+ MESSAGE_FUNC( OnPaste, "OnPaste" );
+
+ // Commands related to the edit menu
+ void OnDescribeUndo();
+
+ // Methods related to the view menu
+ MESSAGE_FUNC( OnToggleProperties, "OnToggleProperties" );
+ MESSAGE_FUNC( OnToggleParticleSystemBrowser, "OnToggleParticleSystemBrowser" );
+ MESSAGE_FUNC( OnToggleParticlePreview, "OnToggleParticlePreview" );
+ MESSAGE_FUNC( OnDefaultLayout, "OnDefaultLayout" );
+
+ // Keybindings
+ KEYBINDING_FUNC( undo, KEY_Z, vgui::MODIFIER_CONTROL, OnUndo, "#undo_help", 0 );
+ KEYBINDING_FUNC( redo, KEY_Z, vgui::MODIFIER_CONTROL | vgui::MODIFIER_SHIFT, OnRedo, "#redo_help", 0 );
+ KEYBINDING_FUNC_NODECLARE( edit_copy, KEY_C, vgui::MODIFIER_CONTROL, OnCopy, "#edit_copy_help", 0 );
+ KEYBINDING_FUNC_NODECLARE( edit_paste, KEY_V, vgui::MODIFIER_CONTROL, OnPaste, "#edit_paste_help", 0 );
+
+ void PerformNew();
+ void OpenFileFromHistory( int slot );
+ void OpenSpecificFile( const char *pFileName );
+ virtual void SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual void OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues );
+
+ // returns the document
+ CPetDoc *GetDocument();
+
+ // Gets at tool windows
+ CParticleSystemPropertiesContainer *GetProperties();
+ CParticleSystemDefinitionBrowser *GetParticleSystemDefinitionBrowser();
+ CParticleSystemPreviewPanel *GetParticlePreview();
+
+ void SetCurrentParticleSystem( CDmeParticleSystemDefinition *pParticleSystem, bool bForceBrowserSelection = true );
+ CDmeParticleSystemDefinition* GetCurrentParticleSystem( void );
+
+private:
+ // Creates a new document
+ void NewDocument( );
+
+ // Loads up a new document
+ bool LoadDocument( const char *pDocName );
+
+ // Updates the menu bar based on the current file
+ void UpdateMenuBar( );
+
+ virtual const char *GetLogoTextureName();
+
+ // Creates, destroys tools
+ void CreateTools( CPetDoc *doc );
+ void DestroyTools();
+
+ // Initializes the tools
+ void InitTools();
+
+ // Shows, toggles tool windows
+ void ToggleToolWindow( Panel *tool, char const *toolName );
+ void ShowToolWindow( Panel *tool, char const *toolName, bool visible );
+
+ // Kills all tool windows
+ void DestroyToolContainers();
+
+private:
+ // Document
+ CPetDoc *m_pDoc;
+
+ // The menu bar
+ CToolFileMenuBar *m_pMenuBar;
+
+ // Element properties for editing material
+ vgui::DHANDLE< CParticleSystemPropertiesContainer > m_hProperties;
+
+ // The entity report
+ vgui::DHANDLE< CParticleSystemDefinitionBrowser > m_hParticleSystemDefinitionBrowser;
+
+ // Particle preview window
+ vgui::DHANDLE< CParticleSystemPreviewPanel > m_hParticlePreview;
+
+ // The currently viewed entity
+ CDmeHandle< CDmeParticleSystemDefinition > m_hCurrentParticleSystem;
+
+ // Separate undo context for the act busy tool
+ CToolWindowFactory< ToolWindow > m_ToolWindowFactory;
+};
+
+extern CPetTool *g_pPetTool;
+
+#endif // PETTOOL_H
diff --git a/tools/sampletool/cbase.cpp b/tools/sampletool/cbase.cpp
new file mode 100644
index 0000000..5ddb045
--- /dev/null
+++ b/tools/sampletool/cbase.cpp
@@ -0,0 +1,9 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "cbase.h"
+
+// This file causes the .pch to be built \ No newline at end of file
diff --git a/tools/sampletool/cbase.h b/tools/sampletool/cbase.h
new file mode 100644
index 0000000..a21b327
--- /dev/null
+++ b/tools/sampletool/cbase.h
@@ -0,0 +1,46 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef CBASE_H
+#define CBASE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#ifdef _WIN32
+// Silence certain warnings
+#pragma warning(disable : 4244) // int or float down-conversion
+#pragma warning(disable : 4305) // int or float data truncation
+#pragma warning(disable : 4201) // nameless struct/union
+#pragma warning(disable : 4511) // copy constructor could not be generated
+#pragma warning(disable : 4675) // resolved overload was found by argument dependent lookup
+#pragma warning(disable : 4706) // assignment within conditional expression
+#endif
+
+#ifdef _DEBUG
+#define DEBUG 1
+#endif
+
+// Misc C-runtime library headers
+#include <math.h>
+#include <stdio.h>
+#include "minmax.h"
+
+// tier 0
+#include "tier0/dbg.h"
+#include "tier0/platform.h"
+#include "basetypes.h"
+
+// tier 1
+#include "tier1/strtools.h"
+#include "utlvector.h"
+#include "mathlib/vmatrix.h"
+#include "filesystem.h"
+
+#include "tier1/ConVar.h"
+#include "icvar.h"
+
+#endif // CBASE_H
diff --git a/tools/sampletool/sampletool.cpp b/tools/sampletool/sampletool.cpp
new file mode 100644
index 0000000..f29a83e
--- /dev/null
+++ b/tools/sampletool/sampletool.cpp
@@ -0,0 +1,342 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core Movie Maker UI API
+//
+//=============================================================================
+#include "cbase.h"
+
+#include "toolutils/basetoolsystem.h"
+#include "toolutils/recentfilelist.h"
+#include "toolutils/toolmenubar.h"
+#include "toolutils/toolswitchmenubutton.h"
+#include "toolutils/toolfilemenubutton.h"
+#include "toolutils/toolmenubutton.h"
+#include "vgui_controls/Menu.h"
+#include "tier1/KeyValues.h"
+#include "toolutils/enginetools_int.h"
+#include "toolframework/ienginetool.h"
+#include "vgui/IInput.h"
+#include "vgui/KeyCode.h"
+#include "vgui_controls/FileOpenDialog.h"
+#include "filesystem.h"
+#include "vgui/ilocalize.h"
+#include "dme_controls/elementpropertiestree.h"
+#include "tier0/icommandline.h"
+#include "materialsystem/imaterialsystem.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "tier3/tier3.h"
+#include "tier2/fileutils.h"
+
+using namespace vgui;
+
+
+const char *GetVGuiControlsModuleName()
+{
+ return "SampleTool";
+}
+
+//-----------------------------------------------------------------------------
+// Connect, disconnect
+//-----------------------------------------------------------------------------
+bool ConnectTools( CreateInterfaceFn factory )
+{
+ return (materials != NULL) && (g_pMatSystemSurface != NULL);
+}
+
+void DisconnectTools( )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Implementation of the sample tool
+//-----------------------------------------------------------------------------
+class CSampleTool : public CBaseToolSystem, public IFileMenuCallbacks
+{
+ DECLARE_CLASS_SIMPLE( CSampleTool, CBaseToolSystem );
+
+public:
+ CSampleTool();
+
+ // Inherited from IToolSystem
+ virtual const char *GetToolName() { return "Sample Tool"; }
+ virtual const char *GetBindingsContextFile() { return "cfg/SampleTool.kb"; }
+ virtual bool Init( );
+ virtual void Shutdown();
+
+ // Inherited from IFileMenuCallbacks
+ virtual int GetFileMenuItemsEnabled( );
+ virtual void AddRecentFilesToMenu( vgui::Menu *menu );
+ virtual bool GetPerforceFileName( char *pFileName, int nMaxLen ) { return false; }
+ virtual vgui::Panel* GetRootPanel() { return this; }
+
+ // Inherited from CBaseToolSystem
+ virtual vgui::HScheme GetToolScheme();
+ virtual vgui::Menu *CreateActionMenu( vgui::Panel *pParent );
+ virtual void OnCommand( const char *cmd );
+ virtual const char *GetRegistryName() { return "SampleTool"; }
+ virtual vgui::MenuBar *CreateMenuBar( CBaseToolSystem *pParent );
+
+public:
+ MESSAGE_FUNC( OnNew, "OnNew" );
+ MESSAGE_FUNC( OnOpen, "OnOpen" );
+ MESSAGE_FUNC( OnSave, "OnSave" );
+ MESSAGE_FUNC( OnSaveAs, "OnSaveAs" );
+ MESSAGE_FUNC( OnClose, "OnClose" );
+ MESSAGE_FUNC( OnCloseNoSave, "OnCloseNoSave" );
+ MESSAGE_FUNC( OnMarkNotDirty, "OnMarkNotDirty" );
+ MESSAGE_FUNC( OnExit, "OnExit" );
+
+ void OpenFileFromHistory( int slot );
+ virtual void SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual void OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues );
+
+private:
+ // Loads up a new document
+ void LoadDocument( const char *pDocName );
+
+ // Updates the menu bar based on the current file
+ void UpdateMenuBar( );
+
+ // Shows element properties
+ void ShowElementProperties( );
+
+ virtual const char *GetLogoTextureName();
+
+};
+
+
+//-----------------------------------------------------------------------------
+// Singleton
+//-----------------------------------------------------------------------------
+CSampleTool *g_pSampleTool = NULL;
+
+void CreateTools()
+{
+ g_pSampleTool = new CSampleTool();
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CSampleTool::CSampleTool()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Init, shutdown
+//-----------------------------------------------------------------------------
+bool CSampleTool::Init( )
+{
+ m_RecentFiles.LoadFromRegistry( GetRegistryName() );
+
+ // NOTE: This has to happen before BaseClass::Init
+// g_pVGuiLocalize->AddFile( "resource/toolsample_%language%.txt" );
+
+ if ( !BaseClass::Init( ) )
+ return false;
+
+ return true;
+}
+
+void CSampleTool::Shutdown()
+{
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ BaseClass::Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get a new scheme to be applied to this tool
+//-----------------------------------------------------------------------------
+vgui::HScheme CSampleTool::GetToolScheme()
+{
+ return vgui::scheme()->LoadSchemeFromFile( "Resource/BoxRocket.res", "SampleTool" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the menu bar
+//-----------------------------------------------------------------------------
+vgui::MenuBar *CSampleTool::CreateMenuBar( CBaseToolSystem *pParent )
+{
+ CToolMenuBar *pMenuBar = new CToolMenuBar( pParent, "Main Menu Bar" );
+
+ // Sets info in the menu bar
+ char title[ 64 ];
+ ComputeMenuBarTitle( title, sizeof( title ) );
+ pMenuBar->SetInfo( title );
+ pMenuBar->SetToolName( GetToolName() );
+
+ // Add menu buttons
+ CToolMenuButton *pFileButton = CreateToolFileMenuButton( pMenuBar, "File", "&File", GetActionTarget(), this );
+ CToolMenuButton *pSwitchButton = CreateToolSwitchMenuButton( pMenuBar, "Switcher", "&Tools", GetActionTarget() );
+
+ pMenuBar->AddButton( pFileButton );
+ pMenuBar->AddButton( pSwitchButton );
+
+ return pMenuBar;
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates the action menu
+//-----------------------------------------------------------------------------
+vgui::Menu *CSampleTool::CreateActionMenu( vgui::Panel *pParent )
+{
+ vgui::Menu *pActionMenu = new Menu( pParent, "ActionMenu" );
+ pActionMenu->AddMenuItem( "#ToolHide", new KeyValues( "Command", "command", "HideActionMenu" ), GetActionTarget() );
+ return pActionMenu;
+}
+
+//-----------------------------------------------------------------------------
+// Inherited from IFileMenuCallbacks
+//-----------------------------------------------------------------------------
+int CSampleTool::GetFileMenuItemsEnabled( )
+{
+ int nFlags = FILE_ALL;
+ if ( m_RecentFiles.IsEmpty() )
+ {
+ nFlags &= ~(FILE_RECENT | FILE_CLEAR_RECENT);
+ }
+ return nFlags;
+}
+
+void CSampleTool::AddRecentFilesToMenu( vgui::Menu *pMenu )
+{
+ m_RecentFiles.AddToMenu( pMenu, GetActionTarget(), "OnRecent" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+void CSampleTool::OnExit()
+{
+ enginetools->Command( "quit\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Handle commands from the action menu and other menus
+//-----------------------------------------------------------------------------
+void CSampleTool::OnCommand( const char *cmd )
+{
+ if ( !V_stricmp( cmd, "HideActionMenu" ) )
+ {
+ if ( GetActionMenu() )
+ {
+ GetActionMenu()->SetVisible( false );
+ }
+ }
+ else if ( const char *pSuffix = StringAfterPrefix( cmd, "OnRecent" ) )
+ {
+ int idx = Q_atoi( pSuffix );
+ OpenFileFromHistory( idx );
+ }
+ else if( const char *pSuffix = StringAfterPrefix( cmd, "OnTool" ) )
+ {
+ int idx = Q_atoi( pSuffix );
+ enginetools->SwitchToTool( idx );
+ }
+ else
+ {
+ BaseClass::OnCommand( cmd );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Command handlers
+//-----------------------------------------------------------------------------
+void CSampleTool::OnNew()
+{
+ // FIXME: Implement
+}
+
+void CSampleTool::OnOpen()
+{
+ OpenFile( "txt" );
+}
+
+bool CSampleTool::OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ // FIXME: Implement
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ return true;
+}
+
+void CSampleTool::OnSave()
+{
+ // FIXME: Implement
+}
+
+void CSampleTool::OnSaveAs()
+{
+ SaveFile( NULL, NULL, 0 );
+}
+
+bool CSampleTool::OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ // FIXME: Implement
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ return true;
+}
+
+void CSampleTool::OnClose()
+{
+ // FIXME: Implement
+}
+
+void CSampleTool::OnCloseNoSave()
+{
+ // FIXME: Implement
+}
+
+void CSampleTool::OnMarkNotDirty()
+{
+ // FIXME: Implement
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the save document query dialog
+//-----------------------------------------------------------------------------
+void CSampleTool::OpenFileFromHistory( int slot )
+{
+ const char *pFileName = m_RecentFiles.GetFile( slot );
+ OnReadFileFromDisk( pFileName, NULL, 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when file operations complete
+//-----------------------------------------------------------------------------
+void CSampleTool::OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues )
+{
+ // FIXME: Implement
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the File browser dialog
+//-----------------------------------------------------------------------------
+void CSampleTool::SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ char pStartingDir[ MAX_PATH ];
+ GetModSubdirectory( NULL, pStartingDir, sizeof(pStartingDir) );
+
+ pDialog->SetTitle( "Choose SampleTool .txt file", true );
+ pDialog->SetStartDirectoryContext( "sample_session", pStartingDir );
+ pDialog->AddFilter( "*.txt", "SampleTool (*.txt)", true );
+}
+
+const char *CSampleTool::GetLogoTextureName()
+{
+ return "vgui/tools/sampletool/sampletool_logo";
+} \ No newline at end of file
diff --git a/tools/sampletool/sampletool.vpc b/tools/sampletool/sampletool.vpc
new file mode 100644
index 0000000..d81f2b1
--- /dev/null
+++ b/tools/sampletool/sampletool.vpc
@@ -0,0 +1,79 @@
+//-----------------------------------------------------------------------------
+// SAMPLETOOL.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin\tools"
+
+$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE,.\,..\common,$SRCDIR\game\shared"
+ $PreprocessorDefinitions "$BASE;SAMPLETOOL_EXPORTS"
+ $Create/UsePrecompiledHeader "Use Precompiled Header (/Yu)"
+ $Create/UsePCHThroughFile "cbase.h"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "$BASE Psapi.lib"
+ }
+}
+
+$Project "Sampletool"
+{
+ $Folder "Source Files"
+ {
+ $File "sampletool.cpp"
+ $File "cbase.cpp"
+ {
+ $Configuration
+ {
+ $Compiler
+ {
+ $Create/UsePrecompiledHeader "Create Precompiled Header (/Yc)"
+ }
+ }
+ }
+
+ $File "$SRCDIR\public\interpolatortypes.cpp" \
+ "$SRCDIR\public\registry.cpp" \
+ "$SRCDIR\public\vgui_controls\vgui_controls.cpp"
+ {
+ $Configuration
+ {
+ $Compiler
+ {
+ $Create/UsePrecompiledHeader "Not Using Precompiled Headers"
+ }
+ }
+ }
+ }
+
+ $Folder "Header Files"
+ {
+ $File "cbase.h"
+ $File "$SRCDIR\public\interpolatortypes.h"
+ $File "$SRCDIR\public\mathlib\mathlib.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib datamodel
+ $Lib dme_controls
+ $Lib dmserializers
+ $Lib mathlib
+ $Lib matsys_controls
+ $Lib movieobjects
+ $Lib sfmobjects
+ $Lib tier2
+ $Lib tier3
+ $Lib toolutils
+ $Lib vgui_controls
+ }
+}
diff --git a/tools/toolutils/BaseToolSystem.cpp b/tools/toolutils/BaseToolSystem.cpp
new file mode 100644
index 0000000..816385d
--- /dev/null
+++ b/tools/toolutils/BaseToolSystem.cpp
@@ -0,0 +1,1156 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core Movie Maker UI API
+//
+//=============================================================================
+
+#include "toolutils/basetoolsystem.h"
+#include "toolframework/ienginetool.h"
+#include "vgui/IPanel.h"
+#include "vgui_controls/Controls.h"
+#include "vgui_controls/Menu.h"
+#include "vgui/ISurface.h"
+#include "vgui_controls/Panel.h"
+#include "vgui_controls/FileOpenDialog.h"
+#include "vgui_controls/MessageBox.h"
+#include "vgui/Cursor.h"
+#include "vgui/iinput.h"
+#include "vgui/ivgui.h"
+#include "vgui_controls/AnimationController.h"
+#include "ienginevgui.h"
+#include "toolui.h"
+#include "toolutils/toolmenubar.h"
+#include "vgui/ilocalize.h"
+#include "toolutils/enginetools_int.h"
+#include "toolutils/vgui_tools.h"
+#include "icvar.h"
+#include "tier1/convar.h"
+#include "datamodel/dmelementfactoryhelper.h"
+#include "filesystem.h"
+#include "vgui_controls/savedocumentquery.h"
+#include "vgui_controls/perforcefilelistframe.h"
+#include "toolutils/miniviewport.h"
+#include "materialsystem/imaterialsystem.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imesh.h"
+#include "toolutils/BaseStatusBar.h"
+#include "movieobjects/movieobjects.h"
+#include "vgui_controls/KeyBoardEditorDialog.h"
+#include "vgui_controls/KeyBindingHelpDialog.h"
+#include "dmserializers/idmserializers.h"
+#include "tier2/renderutils.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+using namespace vgui;
+
+extern IMaterialSystem *MaterialSystem();
+
+class CGlobalFlexController : public IGlobalFlexController
+{
+public:
+ virtual int FindGlobalFlexController( const char *name )
+ {
+ return clienttools->FindGlobalFlexcontroller( name );
+ }
+
+ virtual const char *GetGlobalFlexControllerName( int idx )
+ {
+ return clienttools->GetGlobalFlexControllerName( idx );
+ }
+};
+
+static CGlobalFlexController g_GlobalFlexController;
+
+extern IGlobalFlexController *g_pGlobalFlexController;
+
+//-----------------------------------------------------------------------------
+// Singleton interfaces
+//-----------------------------------------------------------------------------
+IServerTools *servertools = NULL;
+IClientTools *clienttools = NULL;
+
+
+//-----------------------------------------------------------------------------
+// External functions
+//-----------------------------------------------------------------------------
+void RegisterTool( IToolSystem *tool );
+
+
+//-----------------------------------------------------------------------------
+// Base tool system constructor
+//-----------------------------------------------------------------------------
+CBaseToolSystem::CBaseToolSystem( const char *pToolName /*="CBaseToolSystem"*/ ) :
+ BaseClass( NULL, pToolName ),
+ m_pBackground( 0 ),
+ m_pLogo( 0 )
+{
+ RegisterTool( this );
+ SetAutoDelete( false );
+ m_bGameInputEnabled = false;
+ m_bFullscreenMode = false;
+ m_bIsActive = false;
+ m_bFullscreenToolModeEnabled = false;
+ m_MostRecentlyFocused = NULL;
+ SetKeyBoardInputEnabled( true );
+ input()->RegisterKeyCodeUnhandledListener( GetVPanel() );
+
+ m_pFileOpenStateMachine = new vgui::FileOpenStateMachine( this, this );
+ m_pFileOpenStateMachine->AddActionSignalTarget( this );
+}
+
+
+void CBaseToolSystem::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+ SetKeyBoardInputEnabled( true );
+}
+
+//-----------------------------------------------------------------------------
+// Called at the end of engine startup (after client .dll and server .dll have been loaded)
+//-----------------------------------------------------------------------------
+bool CBaseToolSystem::Init( )
+{
+ // Read shared localization info
+ g_pVGuiLocalize->AddFile( "resource/dmecontrols_%language%.txt" );
+ g_pVGuiLocalize->AddFile( "resource/toolshared_%language%.txt" );
+ g_pVGuiLocalize->AddFile( "Resource/vgui_%language%.txt" );
+ g_pVGuiLocalize->AddFile( "Resource/platform_%language%.txt" );
+ g_pVGuiLocalize->AddFile( "resource/boxrocket_%language%.txt" );
+
+ // Create the tool workspace
+ SetParent( VGui_GetToolRootPanel() );
+
+ // Deal with scheme
+ vgui::HScheme hToolScheme = GetToolScheme();
+ if ( hToolScheme != 0 )
+ {
+ SetScheme( hToolScheme );
+ }
+
+ m_KeyBindingsHandle = Panel::CreateKeyBindingsContext( GetBindingsContextFile(), "GAME" );
+ SetKeyBindingsContext( m_KeyBindingsHandle );
+ LoadKeyBindings();
+
+ const char *pszBackground = GetBackgroundTextureName();
+ if ( pszBackground )
+ {
+ m_pBackground = materials->FindMaterial( GetBackgroundTextureName() , TEXTURE_GROUP_VGUI );
+ m_pBackground->IncrementReferenceCount();
+ }
+ const char *pszLogo = GetLogoTextureName();
+ if ( pszLogo )
+ {
+ m_pLogo = materials->FindMaterial( GetLogoTextureName(), TEXTURE_GROUP_VGUI );
+ m_pLogo->IncrementReferenceCount();
+ }
+
+ // Make the tool workspace the size of the screen
+ int w, h;
+ surface()->GetScreenSize( w, h );
+ SetBounds( 0, 0, w, h );
+ SetPaintBackgroundEnabled( true );
+ SetPaintBorderEnabled( false );
+ SetPaintEnabled( false );
+ SetCursor( vgui::dc_none );
+ SetVisible( false );
+
+ // Create the tool UI
+ m_pToolUI = new CToolUI( this, "ToolUI", this );
+
+ // Create the mini viewport
+ m_hMiniViewport = CreateMiniViewport( GetClientArea() );
+ Assert( m_hMiniViewport.Get() );
+
+ return true;
+}
+
+void CBaseToolSystem::ShowMiniViewport( bool state )
+{
+ if ( !m_hMiniViewport.Get() )
+ return;
+
+ m_hMiniViewport->SetVisible( state );
+}
+
+
+void CBaseToolSystem::SetMiniViewportBounds( int x, int y, int width, int height )
+{
+ if ( m_hMiniViewport )
+ {
+ m_hMiniViewport->SetBounds( x, y, width, height );
+ }
+}
+
+void CBaseToolSystem::SetMiniViewportText( const char *pText )
+{
+ if ( m_hMiniViewport )
+ {
+ m_hMiniViewport->SetOverlayText( pText );
+ }
+}
+
+void CBaseToolSystem::GetMiniViewportEngineBounds( int &x, int &y, int &width, int &height )
+{
+ if ( m_hMiniViewport )
+ {
+ m_hMiniViewport->GetEngineBounds( x, y, width, height );
+ }
+}
+
+vgui::Panel *CBaseToolSystem::GetMiniViewport( void )
+{
+ return m_hMiniViewport;
+}
+
+//-----------------------------------------------------------------------------
+// Shut down
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::Shutdown()
+{
+ if ( m_pBackground )
+ {
+ m_pBackground->DecrementReferenceCount();
+ }
+ if ( m_pLogo )
+ {
+ m_pLogo->DecrementReferenceCount();
+ }
+
+ if ( m_hMiniViewport.Get() )
+ {
+ delete m_hMiniViewport.Get();
+ }
+
+ // Make sure anything "marked for deletion"
+ // actually gets deleted before this dll goes away
+ vgui::ivgui()->RunFrame();
+}
+
+
+//-----------------------------------------------------------------------------
+// Can the tool quit?
+//-----------------------------------------------------------------------------
+bool CBaseToolSystem::CanQuit()
+{
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Client, server init + shutdown
+//-----------------------------------------------------------------------------
+bool CBaseToolSystem::ServerInit( CreateInterfaceFn serverFactory )
+{
+ servertools = ( IServerTools * )serverFactory( VSERVERTOOLS_INTERFACE_VERSION, NULL );
+ if ( !servertools )
+ {
+ Error( "CBaseToolSystem::PostInit: Unable to get '%s' interface from game .dll\n", VSERVERTOOLS_INTERFACE_VERSION );
+ }
+
+ return true;
+}
+
+bool CBaseToolSystem::ClientInit( CreateInterfaceFn clientFactory )
+{
+ clienttools = ( IClientTools * )clientFactory( VCLIENTTOOLS_INTERFACE_VERSION, NULL );
+ if ( !clienttools )
+ {
+ Error( "CBaseToolSystem::PostInit: Unable to get '%s' interface from client .dll\n", VCLIENTTOOLS_INTERFACE_VERSION );
+ }
+ else
+ {
+ g_pGlobalFlexController = &g_GlobalFlexController; // don't set this until clienttools is connected
+ }
+
+ return true;
+}
+
+void CBaseToolSystem::ServerShutdown()
+{
+ servertools = NULL;
+}
+
+void CBaseToolSystem::ClientShutdown()
+{
+ clienttools = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Level init, shutdown for server
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::ServerLevelInitPreEntity()
+{
+}
+
+void CBaseToolSystem::ServerLevelInitPostEntity()
+{
+}
+
+void CBaseToolSystem::ServerLevelShutdownPreEntity()
+{
+}
+
+void CBaseToolSystem::ServerLevelShutdownPostEntity()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Think methods
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::ServerFrameUpdatePreEntityThink()
+{
+}
+
+void CBaseToolSystem::Think( bool finalTick )
+{
+ // run vgui animations
+ vgui::GetAnimationController()->UpdateAnimations( enginetools->Time() );
+}
+
+void CBaseToolSystem::PostMessage( HTOOLHANDLE hEntity, KeyValues *message )
+{
+ if ( !Q_stricmp( message->GetName(), "ReleaseLayoffTexture" ) )
+ {
+ if ( m_hMiniViewport.Get() )
+ {
+ m_hMiniViewport->ReleaseLayoffTexture();
+ }
+ return;
+ }
+}
+
+void CBaseToolSystem::ServerFrameUpdatePostEntityThink()
+{
+}
+
+void CBaseToolSystem::ServerPreClientUpdate()
+{
+}
+
+void CBaseToolSystem::ServerPreSetupVisibility()
+{
+}
+
+const char* CBaseToolSystem::GetEntityData( const char *pActualEntityData )
+{
+ return pActualEntityData;
+}
+
+//-----------------------------------------------------------------------------
+// Level init, shutdown for client
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::ClientLevelInitPreEntity()
+{
+}
+
+void CBaseToolSystem::ClientLevelInitPostEntity()
+{
+}
+
+void CBaseToolSystem::ClientLevelShutdownPreEntity()
+{
+}
+
+void CBaseToolSystem::ClientLevelShutdownPostEntity()
+{
+}
+
+void CBaseToolSystem::ClientPreRender()
+{
+}
+
+void CBaseToolSystem::ClientPostRender()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Tool activation/deactivation
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::OnToolActivate()
+{
+ m_bIsActive = true;
+ UpdateUIVisibility( );
+
+ // FIXME: Note that this is necessary because IsGameInputEnabled depends on m_bIsActive at the moment
+ OnModeChanged();
+
+ input()->SetModalSubTree( VGui_GetToolRootPanel(), GetVPanel(), IsGameInputEnabled() );
+ input()->SetModalSubTreeReceiveMessages( !IsGameInputEnabled() );
+
+ m_pToolUI->UpdateMenuBarTitle();
+}
+
+void CBaseToolSystem::OnToolDeactivate()
+{
+ m_bIsActive = false;
+ UpdateUIVisibility( );
+
+ // FIXME: Note that this is necessary because IsGameInputEnabled depends on m_bIsActive at the moment
+ OnModeChanged();
+
+ input()->ReleaseModalSubTree();
+}
+
+//-----------------------------------------------------------------------------
+// Let tool override key events (ie ESC and ~)
+//-----------------------------------------------------------------------------
+bool CBaseToolSystem::TrapKey( ButtonCode_t key, bool down )
+{
+ // Don't hook keyboard if not topmost
+ if ( !m_bIsActive )
+ return false; // didn't trap, continue processing
+
+ // If in fullscreen toolMode, don't let ECSAPE bring up the game menu
+ if ( !m_bGameInputEnabled && m_bFullscreenMode && ( key == KEY_ESCAPE ) )
+ return true; // trapping this key, stop processing
+
+ if ( down )
+ {
+ if ( key == TOGGLE_WINDOWED_KEY_CODE )
+ {
+ SetMode( m_bGameInputEnabled, !m_bFullscreenMode );
+ return true; // trapping this key, stop processing
+ }
+
+ if ( key == TOGGLE_INPUT_KEY_CODE )
+ {
+ if ( input()->IsKeyDown( KEY_LCONTROL ) || input()->IsKeyDown( KEY_RCONTROL ) )
+ {
+ ToggleForceToolCamera();
+ }
+ else
+ {
+ SetMode( !m_bGameInputEnabled, m_bFullscreenMode );
+ }
+ return true; // trapping this key, stop processing
+ }
+
+ // If in IFM mode, let ~ switch to gameMode and toggle console
+ if ( !IsGameInputEnabled() && ( key == '~' || key == '`' ) )
+ {
+ SetMode( true, m_bFullscreenMode );
+ return false; // didn't trap, continue processing
+ }
+ }
+
+ return false; // didn't trap, continue processing
+}
+
+
+//-----------------------------------------------------------------------------
+// Shows, hides the tool ui (menu, client area, status bar)
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::SetToolUIVisible( bool bVisible )
+{
+ if ( bVisible != m_pToolUI->IsVisible() )
+ {
+ m_pToolUI->SetVisible( bVisible );
+ m_pToolUI->InvalidateLayout();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes whether vgui is visible or not
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::UpdateUIVisibility()
+{
+ bool bIsVisible = m_bIsActive && ( !IsGameInputEnabled() || !m_bFullscreenMode );
+ ShowUI( bIsVisible );
+}
+
+
+//-----------------------------------------------------------------------------
+// Changes game input + fullscreen modes
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::EnableFullscreenToolMode( bool bEnable )
+{
+ m_bFullscreenToolModeEnabled = bEnable;
+}
+
+
+//-----------------------------------------------------------------------------
+// Changed whether camera is forced to be tool camera
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::ToggleForceToolCamera()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Changes game input + fullscreen modes
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::SetMode( bool bGameInputEnabled, bool bFullscreen )
+{
+ Assert( m_bIsActive );
+
+ if ( !m_bFullscreenToolModeEnabled )
+ {
+ if ( !bGameInputEnabled )
+ {
+ bFullscreen = false;
+ }
+ }
+
+ if ( ( m_bFullscreenMode == bFullscreen ) && ( m_bGameInputEnabled == bGameInputEnabled ) )
+ return;
+
+ bool bOldGameInputEnabled = m_bGameInputEnabled;
+
+ m_bFullscreenMode = bFullscreen;
+ m_bGameInputEnabled = bGameInputEnabled;
+ UpdateUIVisibility();
+
+ if ( bOldGameInputEnabled != m_bGameInputEnabled )
+ {
+ Warning( "Input is now being sent to the %s\n", m_bGameInputEnabled ? "Game" : "Tools" );
+
+ // The subtree starts at the tool system root panel. If game input is enabled then
+ // the subtree should not receive or process input messages, otherwise it should
+ Assert( input()->GetModalSubTree() );
+ if ( input()->GetModalSubTree() )
+ {
+ input()->SetModalSubTreeReceiveMessages( !m_bGameInputEnabled );
+ }
+ }
+
+ if ( m_pToolUI )
+ {
+ m_pToolUI->UpdateMenuBarTitle();
+ }
+
+ OnModeChanged( );
+}
+
+
+//-----------------------------------------------------------------------------
+// Keybinding
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::LoadKeyBindings()
+{
+ ReloadKeyBindings( m_KeyBindingsHandle );
+}
+
+void CBaseToolSystem::ShowKeyBindingsEditor( Panel *panel, KeyBindingContextHandle_t handle )
+{
+ if ( !m_hKeyBindingsEditor.Get() )
+ {
+ // Show the editor
+ m_hKeyBindingsEditor = new CKeyBoardEditorDialog( GetClientArea(), panel, handle );
+ m_hKeyBindingsEditor->DoModal();
+ }
+}
+
+void CBaseToolSystem::ShowKeyBindingsHelp( Panel *panel, KeyBindingContextHandle_t handle, vgui::KeyCode boundKey, int modifiers )
+{
+ if ( m_hKeyBindingsHelp.Get() )
+ {
+ m_hKeyBindingsHelp->HelpKeyPressed();
+ return;
+ }
+
+ m_hKeyBindingsHelp = new CKeyBindingHelpDialog( GetClientArea(), panel, handle, boundKey, modifiers );
+}
+
+vgui::KeyBindingContextHandle_t CBaseToolSystem::GetKeyBindingsHandle()
+{
+ return m_KeyBindingsHandle;
+}
+
+void CBaseToolSystem::OnEditKeyBindings()
+{
+ Panel *tool = GetMostRecentlyFocusedTool();
+ if ( tool )
+ {
+ ShowKeyBindingsEditor( tool, tool->GetKeyBindingsContext() );
+ }
+}
+
+void CBaseToolSystem::OnKeyBindingHelp()
+{
+ Panel *tool = GetMostRecentlyFocusedTool();
+ if ( tool )
+ {
+ CUtlVector< BoundKey_t * > list;
+ LookupBoundKeys( "keybindinghelp", list );
+ if ( list.Count() > 0 )
+ {
+ ShowKeyBindingsHelp( tool, tool->GetKeyBindingsContext(), (KeyCode)list[ 0 ]->keycode, list[ 0 ]->modifiers );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Registers tool window
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::RegisterToolWindow( vgui::PHandle hPanel )
+{
+ int i = m_Tools.AddToTail( hPanel );
+ m_Tools[i]->SetKeyBindingsContext( m_KeyBindingsHandle );
+}
+
+void CBaseToolSystem::UnregisterAllToolWindows()
+{
+ m_Tools.RemoveAll();
+ m_MostRecentlyFocused = NULL;
+}
+
+Panel *CBaseToolSystem::GetMostRecentlyFocusedTool()
+{
+ VPANEL focus = input()->GetFocus();
+ int c = m_Tools.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ Panel *p = m_Tools[ i ].Get();
+ if ( !p )
+ continue;
+
+ // Not a visible tool
+ if ( !p->GetParent() )
+ continue;
+
+ bool hasFocus = p->HasFocus();
+ bool focusOnChild = focus && ipanel()->HasParent(focus, p->GetVPanel());
+
+ if ( !hasFocus && !focusOnChild )
+ {
+ continue;
+ }
+
+ return p;
+ }
+
+ return m_MostRecentlyFocused.Get();
+}
+
+void CBaseToolSystem::PostMessageToActiveTool( KeyValues *pKeyValues, float flDelay )
+{
+ Panel *pMostRecent = GetMostRecentlyFocusedTool();
+ if ( pMostRecent )
+ {
+ Panel::PostMessage( pMostRecent->GetVPanel(), pKeyValues, flDelay );
+ }
+}
+
+void CBaseToolSystem::PostMessageToActiveTool( const char *msg, float flDelay )
+{
+ Panel *pMostRecent = GetMostRecentlyFocusedTool();
+ if ( pMostRecent )
+ {
+ Panel::PostMessage( pMostRecent->GetVPanel(), new KeyValues( msg ), flDelay );
+ }
+}
+
+void CBaseToolSystem::PostMessageToAllTools( KeyValues *message )
+{
+ int nCount = enginetools->GetToolCount();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ IToolSystem *pToolSystem = const_cast<IToolSystem*>( enginetools->GetToolSystem( i ) );
+ pToolSystem->PostMessage( HTOOLHANDLE_INVALID, message );
+ }
+}
+
+void CBaseToolSystem::OnThink()
+{
+ BaseClass::OnThink();
+
+ VPANEL focus = input()->GetFocus();
+ int c = m_Tools.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ Panel *p = m_Tools[ i ].Get();
+ if ( !p )
+ continue;
+
+ // Not a visible tool
+ if ( !p->GetParent() )
+ continue;
+
+ bool hasFocus = p->HasFocus();
+ bool focusOnChild = focus && ipanel()->HasParent(focus, p->GetVPanel());
+
+ if ( !hasFocus && !focusOnChild )
+ continue;
+
+ m_MostRecentlyFocused = p;
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Let tool override viewport for engine
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::AdjustEngineViewport( int& x, int& y, int& width, int& height )
+{
+ if ( !m_hMiniViewport.Get() )
+ return;
+
+ bool enabled;
+ int vpx, vpy, vpw, vph;
+
+ m_hMiniViewport->GetViewport( enabled, vpx, vpy, vpw, vph );
+
+ if ( !enabled )
+ return;
+
+ x = vpx;
+ y = vpy;
+ width = vpw;
+ height = vph;
+}
+
+//-----------------------------------------------------------------------------
+// Let tool override view/camera
+//-----------------------------------------------------------------------------
+bool CBaseToolSystem::SetupEngineView( Vector &origin, QAngle &angles, float &fov )
+{
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Let tool override microphone
+//-----------------------------------------------------------------------------
+bool CBaseToolSystem::SetupAudioState( AudioState_t &audioState )
+{
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Should the game be allowed to render the view?
+//-----------------------------------------------------------------------------
+bool CBaseToolSystem::ShouldGameRenderView()
+{
+ // Render through mini viewport unless in fullscreen mode
+ if ( !IsVisible() )
+ {
+ return true;
+ }
+
+ if ( !m_hMiniViewport.Get() )
+ return true;
+
+ if ( !m_hMiniViewport->IsVisible() )
+ {
+ return true;
+ }
+
+ // Route through mini viewport
+ return false;
+}
+
+bool CBaseToolSystem::IsThirdPersonCamera()
+{
+ return false;
+}
+
+bool CBaseToolSystem::IsToolRecording()
+{
+ return false;
+}
+
+IMaterialProxy *CBaseToolSystem::LookupProxy( const char *proxyName )
+{
+ return NULL;
+}
+
+
+bool CBaseToolSystem::GetSoundSpatialization( int iUserData, int guid, SpatializationInfo_t& info )
+{
+ // Always hearable (no changes)
+ return true;
+}
+
+void CBaseToolSystem::HostRunFrameBegin()
+{
+}
+
+void CBaseToolSystem::HostRunFrameEnd()
+{
+}
+
+void CBaseToolSystem::RenderFrameBegin()
+{
+ // If we can't see the engine window, do nothing
+ if ( !IsVisible() || !IsActiveTool() )
+ return;
+
+ if ( !m_hMiniViewport.Get() || !m_hMiniViewport->IsVisible() )
+ return;
+
+ m_hMiniViewport->RenderFrameBegin();
+}
+
+void CBaseToolSystem::RenderFrameEnd()
+{
+}
+
+void CBaseToolSystem::VGui_PreRender( int paintMode )
+{
+}
+
+void CBaseToolSystem::VGui_PostRender( int paintMode )
+{
+}
+
+void CBaseToolSystem::VGui_PreSimulate()
+{
+ if ( !m_bIsActive )
+ return;
+
+ // only show the gameUI when in gameMode
+ vgui::VPANEL gameui = enginevgui->GetPanel( PANEL_GAMEUIDLL );
+ if ( gameui != 0 )
+ {
+ bool wantsToBeSeen = IsGameInputEnabled() && (enginetools->IsGamePaused() || !enginetools->IsInGame() || enginetools->IsConsoleVisible());
+ vgui::ipanel()->SetVisible(gameui, wantsToBeSeen);
+ }
+
+ // if there's no map loaded and we're in fullscreen toolMode, switch to gameMode
+ // otherwise there's nothing to see or do...
+ if ( !IsGameInputEnabled() && !IsVisible() && !enginetools->IsInGame() )
+ {
+ SetMode( true, m_bFullscreenMode );
+ }
+}
+
+void CBaseToolSystem::VGui_PostSimulate()
+{
+}
+
+const char *CBaseToolSystem::MapName() const
+{
+ return enginetools->GetCurrentMap();
+}
+
+
+//-----------------------------------------------------------------------------
+// Shows or hides the UI
+//-----------------------------------------------------------------------------
+bool CBaseToolSystem::ShowUI( bool bVisible )
+{
+ bool bPrevVisible = IsVisible();
+ if ( bPrevVisible == bVisible )
+ return bPrevVisible;
+
+ SetMouseInputEnabled( bVisible );
+ SetVisible( bVisible );
+
+ // Hide loading image if using bx movie UI
+ // A bit of a hack because it more or less tunnels through to the client .dll, but the moviemaker assumes
+ // single player anyway...
+ if ( bVisible )
+ {
+ ConVar *pCv = ( ConVar * )cvar->FindVar( "cl_showpausedimage" );
+ if ( pCv )
+ {
+ pCv->SetValue( 0 );
+ }
+ }
+
+ return bPrevVisible;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the action target to sent to panels so that the tool system's OnCommand is called
+//-----------------------------------------------------------------------------
+vgui::Panel *CBaseToolSystem::GetActionTarget()
+{
+ return this;
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes implement this to create a custom menubar
+//-----------------------------------------------------------------------------
+vgui::MenuBar *CBaseToolSystem::CreateMenuBar(CBaseToolSystem *pParent )
+{
+ return new vgui::MenuBar( pParent, "ToolMenuBar" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Derived classes implement this to create a custom status bar, or return NULL for no status bar
+//-----------------------------------------------------------------------------
+vgui::Panel *CBaseToolSystem::CreateStatusBar( vgui::Panel *pParent )
+{
+ return new CBaseStatusBar( this, "Status Bar" );
+}
+
+//-----------------------------------------------------------------------------
+// Gets at the action menu
+//-----------------------------------------------------------------------------
+vgui::Menu *CBaseToolSystem::GetActionMenu()
+{
+ return m_hActionMenu;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the client area
+//-----------------------------------------------------------------------------
+vgui::Panel* CBaseToolSystem::GetClientArea()
+{
+ return m_pToolUI->GetClientArea();
+}
+
+
+//-----------------------------------------------------------------------------
+// Pops up the action menu
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::OnMousePressed( vgui::MouseCode code )
+{
+ if ( code == MOUSE_RIGHT )
+ {
+ InitActionMenu();
+ }
+ else
+ {
+ BaseClass::OnMousePressed( code );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates the action menu
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::InitActionMenu()
+{
+ ShutdownActionMenu();
+
+ // Let the tool system create the action menu
+ m_hActionMenu = CreateActionMenu( this );
+
+ if ( m_hActionMenu.Get() )
+ {
+ m_hActionMenu->SetVisible(true);
+ PositionActionMenu();
+ m_hActionMenu->RequestFocus();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Destroy action menu
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::ShutdownActionMenu()
+{
+ if ( m_hActionMenu.Get() )
+ {
+ m_hActionMenu->MarkForDeletion();
+ m_hActionMenu = NULL;
+ }
+}
+
+void CBaseToolSystem::UpdateMenu( vgui::Menu *menu )
+{
+ // Nothing
+}
+
+//-----------------------------------------------------------------------------
+// Positions the action menu when it's time to pop it up
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::PositionActionMenu()
+{
+ // get cursor position, this is local to this text edit window
+ int cursorX, cursorY;
+ input()->GetCursorPos(cursorX, cursorY);
+
+ // relayout the menu immediately so that we know it's size
+ m_hActionMenu->InvalidateLayout(true);
+
+ // Get the menu size
+ int menuWide, menuTall;
+ m_hActionMenu->GetSize( menuWide, menuTall );
+
+ // work out where the cursor is and therefore the best place to put the menu
+ int wide, tall;
+ GetSize( wide, tall );
+
+ if (wide - menuWide > cursorX)
+ {
+ // menu hanging right
+ if (tall - menuTall > cursorY)
+ {
+ // menu hanging down
+ m_hActionMenu->SetPos(cursorX, cursorY);
+ }
+ else
+ {
+ // menu hanging up
+ m_hActionMenu->SetPos(cursorX, cursorY - menuTall);
+ }
+ }
+ else
+ {
+ // menu hanging left
+ if (tall - menuTall > cursorY)
+ {
+ // menu hanging down
+ m_hActionMenu->SetPos(cursorX - menuWide, cursorY);
+ }
+ else
+ {
+ // menu hanging up
+ m_hActionMenu->SetPos(cursorX - menuWide, cursorY - menuTall);
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Handles the clear recent files message
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::OnClearRecent()
+{
+ m_RecentFiles.Clear();
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called by the file open state machine
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::OnFileStateMachineFinished( KeyValues *pKeyValues )
+{
+ KeyValues *pContext = pKeyValues->GetFirstTrueSubKey();
+ bool bWroteFile = pKeyValues->GetInt( "wroteFile", 0 ) != 0;
+ vgui::FileOpenStateMachine::CompletionState_t state = (vgui::FileOpenStateMachine::CompletionState_t)pKeyValues->GetInt( "completionState", vgui::FileOpenStateMachine::IN_PROGRESS );
+ const char *pFileType = pKeyValues->GetString( "fileType" );
+ OnFileOperationCompleted( pFileType, bWroteFile, state, pContext );
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the File browser dialog
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::OpenFile( const char *pOpenFileType, const char *pSaveFileName, const char *pSaveFileType, int nFlags, KeyValues *pContextKeyValues )
+{
+ m_pFileOpenStateMachine->OpenFile( pOpenFileType, pContextKeyValues, pSaveFileName, pSaveFileType, nFlags );
+}
+
+void CBaseToolSystem::OpenFile( const char *pOpenFileName, const char *pOpenFileType, const char *pSaveFileName, const char *pSaveFileType, int nFlags, KeyValues *pContextKeyValues )
+{
+ m_pFileOpenStateMachine->OpenFile( pOpenFileName, pOpenFileType, pContextKeyValues, pSaveFileName, pSaveFileType, nFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Used to save a specified file, and deal with all the lovely dialogs
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::SaveFile( const char *pFileName, const char *pFileType, int nFlags, KeyValues *pContextKeyValues )
+{
+ m_pFileOpenStateMachine->SaveFile( pContextKeyValues, pFileName, pFileType, nFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Paints the background
+//-----------------------------------------------------------------------------
+void CBaseToolSystem::PaintBackground()
+{
+ int w, h;
+ GetSize( w, h );
+
+ int x, y;
+ GetPos( x, y );
+ LocalToScreen( x, y );
+
+ CMatRenderContextPtr pRenderContext( materials );
+ if ( m_pBackground )
+ {
+ int texWide = m_pBackground->GetMappingWidth();
+ int texTall = m_pBackground->GetMappingHeight();
+
+ float maxu = (float)w / (float)texWide;
+ float maxv = (float)h / (float)texTall;
+
+ RenderQuad( m_pBackground, x, y, w, h, surface()->GetZPos(), 0.0f, 0.0f, maxu, maxv, Color( 255, 255, 255, 255 ) );
+ }
+
+ bool hasDoc = HasDocument();
+ if ( m_pLogo )
+ {
+ int texWide = m_pLogo->GetMappingWidth();
+ float logoAspectRatio = 0.442;
+
+ if ( hasDoc )
+ {
+ int logoW = texWide / 2;
+ int logoH = logoW * logoAspectRatio;
+
+ x = w - logoW - 15;
+ y = h - logoH - 30;
+
+ w = logoW;
+ h = logoH;
+ }
+ else
+ {
+ int logoW = texWide;
+ int logoH = logoW * logoAspectRatio;
+
+ x = ( w - logoW ) / 2;
+ y = ( h - logoH ) / 2;
+
+ w = logoW;
+ h = logoH;
+ }
+
+ int alpha = hasDoc ? 0 : 255;
+
+ RenderQuad( m_pLogo, x, y, w, h, surface()->GetZPos(), 0.0f, 0.0f, 1.0f, 1.0f, Color( 255, 255, 255, alpha ) );
+ }
+}
+
+const char *CBaseToolSystem::GetBackgroundTextureName()
+{
+ return "vgui/tools/ifm/ifm_background";
+}
+
+bool CBaseToolSystem::HasDocument()
+{
+ return false;
+}
+
+CMiniViewport *CBaseToolSystem::CreateMiniViewport( vgui::Panel *parent )
+{
+ int w, h;
+ surface()->GetScreenSize( w, h );
+
+ CMiniViewport *vp = new CMiniViewport( parent, "MiniViewport" );
+ Assert( vp );
+ vp->SetVisible( true );
+ int menuBarHeight = 28;
+ int titleBarHeight = 22;
+ int offset = 4;
+ vp->SetBounds( ( 2 * w / 3 ) - offset, menuBarHeight + offset, w / 3, h / 3 + titleBarHeight);
+ return vp;
+}
+
+void CBaseToolSystem::ComputeMenuBarTitle( char *buf, size_t buflen )
+{
+ Q_snprintf( buf, buflen, ": %s [ %s - Switch Mode ] [ %s - Full Screen ]", IsGameInputEnabled() ? "Game Mode" : "Tool Mode", TOGGLE_INPUT_KEY_NAME, TOGGLE_WINDOWED_KEY_NAME );
+}
+
+void CBaseToolSystem::OnUnhandledMouseClick( int code )
+{
+ if ( (MouseCode)code == MOUSE_LEFT )
+ {
+ // If tool ui is visible and we're running game in a window
+ // and they click on the ifm it'll be unhandled, but in this case
+ // we'll switch back to the IFM mode
+ if ( !IsFullscreen() && IsGameInputEnabled() )
+ {
+ SetMode( false, m_bFullscreenMode );
+ }
+ }
+}
diff --git a/tools/toolutils/ConsolePage.cpp b/tools/toolutils/ConsolePage.cpp
new file mode 100644
index 0000000..b2ff4d5
--- /dev/null
+++ b/tools/toolutils/ConsolePage.cpp
@@ -0,0 +1,45 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#include "toolutils/ConsolePage.h"
+#include "toolutils/enginetools_int.h"
+#include "toolframework/ienginetool.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CConsolePage::CConsolePage( Panel *parent, bool bStatusVersion ) : BaseClass( parent, "ToolsConsole", bStatusVersion )
+{
+ AddActionSignalTarget( this );
+}
+
+
+//-----------------------------------------------------------------------------
+// Submits a command
+//-----------------------------------------------------------------------------
+void CConsolePage::OnCommandSubmitted( const char *pCommand )
+{
+ enginetools->Command( pCommand );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets up colors
+//-----------------------------------------------------------------------------
+void CConsolePage::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ m_PrintColor = GetSchemeColor("IFMConsole.TextColor", pScheme);
+ m_DPrintColor = GetSchemeColor("IFMConsole.DevTextColor", pScheme);
+}
diff --git a/tools/toolutils/ToolFileMenuButton.cpp b/tools/toolutils/ToolFileMenuButton.cpp
new file mode 100644
index 0000000..36070fb
--- /dev/null
+++ b/tools/toolutils/ToolFileMenuButton.cpp
@@ -0,0 +1,251 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Standard file menu
+//
+//=============================================================================
+
+#include "toolutils/toolfilemenubutton.h"
+#include "toolutils/toolmenubutton.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlstring.h"
+#include "vgui_controls/menu.h"
+#include "vgui_controls/frame.h"
+#include "vgui_controls/button.h"
+#include "vgui_controls/listpanel.h"
+#include "toolutils/enginetools_int.h"
+#include "p4lib/ip4.h"
+#include "vgui_controls/perforcefilelistframe.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Global function to create the file menu
+//-----------------------------------------------------------------------------
+CToolMenuButton* CreateToolFileMenuButton( vgui::Panel *parent, const char *panelName,
+ const char *text, vgui::Panel *pActionTarget, IFileMenuCallbacks *pCallbacks )
+{
+ return new CToolFileMenuButton( parent, panelName, text, pActionTarget, pCallbacks );
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CToolFileMenuButton::CToolFileMenuButton( vgui::Panel *pParent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget, IFileMenuCallbacks *pFileMenuCallback ) :
+ BaseClass( pParent, panelName, text, pActionSignalTarget ), m_pFileMenuCallback( pFileMenuCallback )
+{
+ Assert( pFileMenuCallback );
+
+ AddMenuItem( "new", "#ToolFileNew", new KeyValues( "OnNew" ), pActionSignalTarget, NULL, "file_new" );
+ AddMenuItem( "open", "#ToolFileOpen", new KeyValues( "OnOpen" ), pActionSignalTarget, NULL, "file_open" );
+ AddMenuItem( "save", "#ToolFileSave", new KeyValues( "OnSave" ), pActionSignalTarget, NULL, "file_save" );
+ AddMenuItem( "saveas", "#ToolFileSaveAs", new KeyValues( "OnSaveAs" ), pActionSignalTarget );
+ AddMenuItem( "close", "#ToolFileClose", new KeyValues( "OnClose" ), pActionSignalTarget );
+ AddSeparator();
+
+ // Add the Perforce menu options only if there is a valid P4 interface (SDK users won't have this)
+ if ( p4 )
+ {
+ m_pPerforce = new vgui::Menu( this, "Perforce" );
+ m_pMenu->AddCascadingMenuItem( "#ToolPerforce", this, m_pPerforce );
+ m_nPerforceAdd = m_pPerforce->AddMenuItem( "perforce_add", "#ToolPerforceAdd", new KeyValues( "OnPerforceAdd" ), this );
+ m_nPerforceOpen = m_pPerforce->AddMenuItem( "perforce_open", "#ToolPerforceOpen", new KeyValues( "OnPerforceOpen" ), this );
+ m_nPerforceRevert = m_pPerforce->AddMenuItem( "perforce_revert", "#ToolPerforceRevert", new KeyValues( "OnPerforceRevert" ), this );
+ m_nPerforceSubmit = m_pPerforce->AddMenuItem( "perforce_submit", "#ToolPerforceSubmit", new KeyValues( "OnPerforceSubmit" ), this );
+ m_pPerforce->AddSeparator();
+ m_nPerforceP4Win = m_pPerforce->AddMenuItem( "perforce_p4win", "#ToolPerforceP4Win", new KeyValues( "OnPerforceP4Win" ), this );
+ m_nPerforceListOpenFiles = m_pPerforce->AddMenuItem( "perforce_listopenfiles", "#ToolPerforceListOpenFiles", new KeyValues( "OnPerforceListOpenFiles" ), this );
+ }
+
+ m_pRecentFiles = new vgui::Menu( this, "RecentFiles" );
+ m_nRecentFiles = m_pMenu->AddCascadingMenuItem( "#ToolFileRecent", pActionSignalTarget, m_pRecentFiles );
+
+ AddMenuItem( "clearrecent", "#ToolFileClearRecent", new KeyValues ( "OnClearRecent" ), pActionSignalTarget );
+ AddSeparator();
+ AddMenuItem( "exit", "#ToolFileExit", new KeyValues ( "OnExit" ), pActionSignalTarget );
+
+ SetMenu( m_pMenu );
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets called when the menu is shown
+//-----------------------------------------------------------------------------
+void CToolFileMenuButton::OnShowMenu( vgui::Menu *menu )
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ int nEnableMask = m_pFileMenuCallback->GetFileMenuItemsEnabled();
+
+ int id = m_Items.Find( "new" );
+ SetItemEnabled( id, (nEnableMask & IFileMenuCallbacks::FILE_NEW) != 0 );
+ id = m_Items.Find( "open" );
+ SetItemEnabled( id, (nEnableMask & IFileMenuCallbacks::FILE_OPEN) != 0 );
+ id = m_Items.Find( "save" );
+ SetItemEnabled( id, (nEnableMask & IFileMenuCallbacks::FILE_SAVE) != 0 );
+ id = m_Items.Find( "saveas" );
+ SetItemEnabled( id, (nEnableMask & IFileMenuCallbacks::FILE_SAVEAS) != 0 );
+ id = m_Items.Find( "close" );
+ SetItemEnabled( id, (nEnableMask & IFileMenuCallbacks::FILE_CLOSE) != 0 );
+ id = m_Items.Find( "clearrecent" );
+ SetItemEnabled( id, (nEnableMask & IFileMenuCallbacks::FILE_CLEAR_RECENT) != 0 );
+
+ m_pRecentFiles->DeleteAllItems();
+
+ if ( (nEnableMask & IFileMenuCallbacks::FILE_RECENT) == 0 )
+ {
+ m_pMenu->SetItemEnabled( m_nRecentFiles, false );
+ }
+ else
+ {
+ m_pMenu->SetItemEnabled( m_nRecentFiles, true );
+ m_pFileMenuCallback->AddRecentFilesToMenu( m_pRecentFiles );
+ }
+
+ // We only have the Perforce menu items if we have valid p4 interface
+ if ( p4 )
+ {
+ bool bP4Connected = p4->IsConnectedToServer();
+ char pPerforceFile[MAX_PATH];
+ if ( bP4Connected && m_pFileMenuCallback->GetPerforceFileName( pPerforceFile, sizeof(pPerforceFile) ) )
+ {
+ bool bIsUnnamed = !Q_IsAbsolutePath( pPerforceFile );
+ bool bOpenedForEdit = p4->GetFileState( pPerforceFile ) != P4FILE_UNOPENED;
+ bool bFileInPerforce = p4->IsFileInPerforce( pPerforceFile );
+
+ m_pPerforce->SetItemEnabled( m_nPerforceAdd, !bIsUnnamed && !bFileInPerforce && !bOpenedForEdit );
+ m_pPerforce->SetItemEnabled( m_nPerforceOpen, !bIsUnnamed && bFileInPerforce && !bOpenedForEdit );
+ m_pPerforce->SetItemEnabled( m_nPerforceRevert, !bIsUnnamed && bOpenedForEdit );
+ m_pPerforce->SetItemEnabled( m_nPerforceSubmit, !bIsUnnamed && bOpenedForEdit );
+ m_pPerforce->SetItemEnabled( m_nPerforceP4Win, !bIsUnnamed && bFileInPerforce || bOpenedForEdit );
+ m_pPerforce->SetItemEnabled( m_nPerforceListOpenFiles, true );
+ }
+ else
+ {
+ m_pPerforce->SetItemEnabled( m_nPerforceAdd, false );
+ m_pPerforce->SetItemEnabled( m_nPerforceOpen, false );
+ m_pPerforce->SetItemEnabled( m_nPerforceRevert, false );
+ m_pPerforce->SetItemEnabled( m_nPerforceSubmit, false );
+ m_pPerforce->SetItemEnabled( m_nPerforceP4Win, false );
+ m_pPerforce->SetItemEnabled( m_nPerforceListOpenFiles, bP4Connected );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Perforce functions
+//-----------------------------------------------------------------------------
+void CToolFileMenuButton::OnPerforceAdd( )
+{
+ char pPerforceFile[MAX_PATH];
+ if ( m_pFileMenuCallback->GetPerforceFileName( pPerforceFile, sizeof(pPerforceFile) ) )
+ {
+ CPerforceFileListFrame *pPerforceFrame = new CPerforceFileListFrame( m_pFileMenuCallback->GetRootPanel(), "Add Movie File to Perforce?", "Movie File", PERFORCE_ACTION_FILE_ADD );
+ pPerforceFrame->AddFile( pPerforceFile );
+ pPerforceFrame->DoModal( );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Check out a file
+//-----------------------------------------------------------------------------
+void CToolFileMenuButton::OnPerforceOpen( )
+{
+ char pPerforceFile[MAX_PATH];
+ if ( m_pFileMenuCallback->GetPerforceFileName( pPerforceFile, sizeof(pPerforceFile) ) )
+ {
+ CPerforceFileListFrame *pPerforceFrame = new CPerforceFileListFrame( m_pFileMenuCallback->GetRootPanel(), "Check Out Movie File from Perforce?", "Movie File", PERFORCE_ACTION_FILE_EDIT );
+ pPerforceFrame->AddFile( pPerforceFile );
+ pPerforceFrame->DoModal( );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Revert a file
+//-----------------------------------------------------------------------------
+void CToolFileMenuButton::OnPerforceRevert( )
+{
+ char pPerforceFile[MAX_PATH];
+ if ( m_pFileMenuCallback->GetPerforceFileName( pPerforceFile, sizeof(pPerforceFile) ) )
+ {
+ CPerforceFileListFrame *pPerforceFrame = new CPerforceFileListFrame( m_pFileMenuCallback->GetRootPanel(), "Revert Movie File Changes from Perforce?", "Movie File", PERFORCE_ACTION_FILE_REVERT );
+ pPerforceFrame->AddFile( pPerforceFile );
+ pPerforceFrame->DoModal( );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Submit a file
+//-----------------------------------------------------------------------------
+void CToolFileMenuButton::OnPerforceSubmit( )
+{
+ char pPerforceFile[MAX_PATH];
+ if ( m_pFileMenuCallback->GetPerforceFileName( pPerforceFile, sizeof(pPerforceFile) ) )
+ {
+ CPerforceFileListFrame *pPerforceFrame = new CPerforceFileListFrame( m_pFileMenuCallback->GetRootPanel(), "Submit Movie File Changes to Perforce?", "Movie File", PERFORCE_ACTION_FILE_SUBMIT );
+ pPerforceFrame->AddFile( pPerforceFile );
+ pPerforceFrame->DoModal( );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Open a file in p4win
+//-----------------------------------------------------------------------------
+void CToolFileMenuButton::OnPerforceP4Win( )
+{
+ char pPerforceFile[MAX_PATH];
+ if ( m_pFileMenuCallback->GetPerforceFileName( pPerforceFile, sizeof(pPerforceFile) ) )
+ {
+ if ( p4->IsFileInPerforce( pPerforceFile ) )
+ {
+ p4->OpenFileInP4Win( pPerforceFile );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Show a file in p4win
+//-----------------------------------------------------------------------------
+void CToolFileMenuButton::OnPerforceListOpenFiles( )
+{
+ CUtlVector<P4File_t> openedFiles;
+ p4->GetOpenedFileListInPath( "GAME", openedFiles );
+ COperationFileListFrame *pOpenedFiles = new COperationFileListFrame( m_pFileMenuCallback->GetRootPanel(), "Opened Files In Perforce", "File Name", false, true );
+
+ int nCount = openedFiles.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ const char *pOpenType = NULL;
+ switch( openedFiles[i].m_eOpenState )
+ {
+ case P4FILE_OPENED_FOR_ADD:
+ pOpenType = "Add";
+ break;
+ case P4FILE_OPENED_FOR_EDIT:
+ pOpenType = "Edit";
+ break;
+ case P4FILE_OPENED_FOR_DELETE:
+ pOpenType = "Delete";
+ break;
+ case P4FILE_OPENED_FOR_INTEGRATE:
+ pOpenType = "Integrate";
+ break;
+ }
+
+ if ( pOpenType )
+ {
+ pOpenedFiles->AddOperation( pOpenType, p4->String( openedFiles[i].m_sLocalFile ) );
+ }
+ }
+
+ pOpenedFiles->DoModal( );
+}
diff --git a/tools/toolutils/ToolHelpMenuButton.cpp b/tools/toolutils/ToolHelpMenuButton.cpp
new file mode 100644
index 0000000..6ee6567
--- /dev/null
+++ b/tools/toolutils/ToolHelpMenuButton.cpp
@@ -0,0 +1,60 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core Movie Maker UI API
+//
+//=============================================================================
+
+#include "toolutils/toolswitchmenubutton.h"
+#include "vgui_controls/panel.h"
+#include "toolutils/toolmenubutton.h"
+#include "toolutils/enginetools_int.h"
+#include "tier1/KeyValues.h"
+#include "vgui_controls/menu.h"
+#include "vgui/ILocalize.h"
+#include "toolframework/ienginetool.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Menu to switch between tools
+//-----------------------------------------------------------------------------
+class CToolHelpMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CToolHelpMenuButton, CToolMenuButton );
+
+public:
+ CToolHelpMenuButton( char const *toolName, char const *helpBinding, vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionTarget );
+};
+
+
+//-----------------------------------------------------------------------------
+// Global function to create the help menu
+//-----------------------------------------------------------------------------
+CToolMenuButton* CreateToolHelpMenuButton( char const *toolName, char const *helpBinding, vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionTarget )
+{
+ return new CToolHelpMenuButton( toolName, helpBinding, parent, panelName, text, pActionTarget );
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CToolHelpMenuButton::CToolHelpMenuButton( char const *toolName, char const *helpBinding, vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionTarget ) :
+ BaseClass( parent, panelName, text, pActionTarget )
+{
+ wchar_t *fmt = g_pVGuiLocalize->Find( "ToolHelpShowHelp" );
+ if ( fmt )
+ {
+ wchar_t desc[ 256 ];
+ g_pVGuiLocalize->ConvertANSIToUnicode( toolName, desc, sizeof( desc ) );
+
+ wchar_t buf[ 512 ];
+ g_pVGuiLocalize->ConstructString( buf, sizeof( buf ), fmt, 1, desc );
+
+ AddMenuItem( "help", buf, new KeyValues( "OnHelp" ), pActionTarget, NULL, helpBinding );
+ }
+
+ SetMenu(m_pMenu);
+}
diff --git a/tools/toolutils/ToolMenuButton.cpp b/tools/toolutils/ToolMenuButton.cpp
new file mode 100644
index 0000000..86ecaec
--- /dev/null
+++ b/tools/toolutils/ToolMenuButton.cpp
@@ -0,0 +1,185 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core Movie Maker UI API
+//
+//=============================================================================
+
+#include "toolutils/toolmenubutton.h"
+#include "toolutils/toolmenubar.h"
+#include "toolutils/basetoolsystem.h"
+#include "vgui_controls/menu.h"
+#include "vgui_controls/KeyBindingMap.h"
+#include "vgui/ILocalize.h"
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CToolMenuButton::CToolMenuButton( Panel *parent, const char *panelName, const char *text, Panel *actionTarget ) :
+ BaseClass( parent, panelName, text ),
+ m_pActionTarget( actionTarget )
+{
+ m_pMenu = new Menu( this, "Menu" );
+}
+
+void CToolMenuButton::Reset()
+{
+ m_Items.RemoveAll();
+ m_pMenu->DeleteAllItems();
+}
+
+int CToolMenuButton::AddMenuItem( char const *itemName, const char *itemText, KeyValues *message, Panel *target, const KeyValues *userData /*= NULL*/, char const *kbcommandname /*= NULL*/ )
+{
+ int id = m_pMenu->AddMenuItem(itemText, message, target, userData);
+ MenuItem_t item;
+ item.m_ItemID = id;
+ if ( kbcommandname )
+ {
+ item.m_KeyBinding = kbcommandname;
+ }
+ m_Items.Insert( itemName, item );
+ return id;
+}
+
+int CToolMenuButton::AddCheckableMenuItem( char const *itemName, const char *itemText, KeyValues *message, Panel *target, const KeyValues *userData /*= NULL*/, char const *kbcommandname /*= NULL*/ )
+{
+ int id = m_pMenu->AddCheckableMenuItem(itemText, message, target, userData);
+ MenuItem_t item;
+ item.m_ItemID = id;
+ if ( kbcommandname )
+ {
+ item.m_KeyBinding = kbcommandname;
+ }
+ m_Items.Insert( itemName, item );
+ return id;
+}
+
+int CToolMenuButton::AddMenuItem( char const *itemName, const wchar_t *itemText, KeyValues *message, Panel *target, const KeyValues *userData /*= NULL*/, char const *kbcommandname /*= NULL*/ )
+{
+ int id = m_pMenu->AddMenuItem(itemName, itemText, message, target, userData);
+ MenuItem_t item;
+ item.m_ItemID = id;
+ if ( kbcommandname )
+ {
+ item.m_KeyBinding = kbcommandname;
+ }
+ m_Items.Insert( itemName, item );
+ return id;
+}
+
+int CToolMenuButton::AddCheckableMenuItem( char const *itemName, const wchar_t *itemText, KeyValues *message, Panel *target, const KeyValues *userData /*= NULL*/, char const *kbcommandname /*= NULL*/ )
+{
+ int id = m_pMenu->AddCheckableMenuItem(itemName, itemText, message, target, userData);
+ MenuItem_t item;
+ item.m_ItemID = id;
+ if ( kbcommandname )
+ {
+ item.m_KeyBinding = kbcommandname;
+ }
+ m_Items.Insert( itemName, item );
+ return id;
+}
+
+void CToolMenuButton::AddSeparator()
+{
+ m_pMenu->AddSeparator();
+}
+
+void CToolMenuButton::SetItemEnabled( int itemID, bool state )
+{
+ m_pMenu->SetItemEnabled( m_Items[ itemID ].m_ItemID, state );
+}
+
+int CToolMenuButton::FindMenuItem( char const *itemName )
+{
+ int id = m_Items.Find( itemName );
+ if ( id == m_Items.InvalidIndex() )
+ return -1;
+ return m_Items[ id ].m_ItemID;
+}
+
+void CToolMenuButton::AddSeparatorAfterItem( char const *itemName )
+{
+ int id = FindMenuItem( itemName );
+ if ( id != -1 )
+ {
+ m_pMenu->AddSeparatorAfterItem( id );
+ }
+}
+
+void CToolMenuButton::MoveMenuItem( int itemID, int moveBeforeThisItemID )
+{
+ m_pMenu->MoveMenuItem( itemID, moveBeforeThisItemID );
+}
+
+void CToolMenuButton::SetCurrentKeyBindingLabel( char const *itemName, char const *binding )
+{
+ int id = FindMenuItem( itemName );
+ if ( id != -1 )
+ {
+ m_pMenu->SetCurrentKeyBinding( id, binding );
+ }
+}
+
+
+
+void CToolMenuButton::UpdateMenuItemKeyBindings()
+{
+ if ( !m_pActionTarget )
+ return;
+
+ int c = m_Items.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ if ( !m_Items[ i ].m_KeyBinding.IsValid() )
+ continue;
+
+ char const *bindingName = m_Items[ i ].m_KeyBinding.String();
+
+ CUtlVector< BoundKey_t * > list;
+ m_pActionTarget->LookupBoundKeys( bindingName, list );
+ if ( list.Count() <= 0 )
+ continue;
+
+ BoundKey_t *kb = list[ 0 ];
+ Assert( kb );
+
+ // Found it, now convert to binding string
+ // First do modifiers
+ wchar_t sz[ 256 ];
+ wcsncpy( sz, Panel::KeyCodeModifiersToDisplayString( (KeyCode)kb->keycode, kb->modifiers ), 256 );
+ sz[ 255 ] = L'\0';
+
+ char ansi[ 512 ];
+ g_pVGuiLocalize->ConvertUnicodeToANSI( sz, ansi, sizeof( ansi ) );
+ m_pMenu->SetCurrentKeyBinding( m_Items[ i ].m_ItemID, ansi );
+
+ }
+}
+
+void CToolMenuButton::OnShowMenu( Menu *menu )
+{
+ CToolMenuBar *bar = dynamic_cast< CToolMenuBar * >( GetParent() );
+ if ( bar )
+ {
+ CBaseToolSystem *sys = bar->GetToolSystem();
+ if ( sys )
+ {
+ sys->UpdateMenu( menu );
+ }
+ }
+
+ UpdateMenuItemKeyBindings();
+
+ m_pMenu->ForceCalculateWidth();
+}
+
+vgui::Menu *CToolMenuButton::GetMenu()
+{
+ return m_pMenu;
+}
+
+
diff --git a/tools/toolutils/ToolSwitchMenuButton.cpp b/tools/toolutils/ToolSwitchMenuButton.cpp
new file mode 100644
index 0000000..46f0c7c
--- /dev/null
+++ b/tools/toolutils/ToolSwitchMenuButton.cpp
@@ -0,0 +1,72 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core Movie Maker UI API
+//
+//=============================================================================
+
+#include "toolutils/toolswitchmenubutton.h"
+#include "vgui_controls/panel.h"
+#include "toolutils/toolmenubutton.h"
+#include "toolutils/enginetools_int.h"
+#include "tier1/KeyValues.h"
+#include "vgui_controls/menu.h"
+#include "toolframework/ienginetool.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Menu to switch between tools
+//-----------------------------------------------------------------------------
+class CToolSwitchMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CToolSwitchMenuButton, CToolMenuButton );
+
+public:
+ CToolSwitchMenuButton( vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+};
+
+
+//-----------------------------------------------------------------------------
+// Global function to create the switch menu
+//-----------------------------------------------------------------------------
+CToolMenuButton* CreateToolSwitchMenuButton( vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionTarget )
+{
+ return new CToolSwitchMenuButton( parent, panelName, text, pActionTarget );
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CToolSwitchMenuButton::CToolSwitchMenuButton( vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionTarget ) :
+ BaseClass( parent, panelName, text, pActionTarget )
+{
+ SetMenu(m_pMenu);
+}
+
+
+//-----------------------------------------------------------------------------
+// Is called when the menu is made visible
+//-----------------------------------------------------------------------------
+void CToolSwitchMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+
+ Reset();
+
+ int c = enginetools->GetToolCount();
+ for ( int i = 0 ; i < c; ++i )
+ {
+ char const *toolname = enginetools->GetToolName( i );
+
+ char toolcmd[ 32 ];
+ Q_snprintf( toolcmd, sizeof( toolcmd ), "OnTool%i", i );
+
+ int id = AddCheckableMenuItem( toolname, toolname, new KeyValues ( "Command", "command", toolcmd ), m_pActionTarget );
+ m_pMenu->SetItemEnabled( id, true );
+ m_pMenu->SetMenuItemChecked( id, enginetools->IsTopmostTool( enginetools->GetToolSystem( i ) ) );
+ }
+}
diff --git a/tools/toolutils/ToolUI.cpp b/tools/toolutils/ToolUI.cpp
new file mode 100644
index 0000000..012811c
--- /dev/null
+++ b/tools/toolutils/ToolUI.cpp
@@ -0,0 +1,118 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// The tool UI has 4 purposes:
+// 1) Create the menu bar and client area (lies under the menu bar)
+// 2) Forward all mouse messages to the tool workspace so action menus work
+// 3) Forward all commands to the tool system so all smarts can reside there
+// 4) Control the size of the menu bar + the working area
+//=============================================================================
+
+#include "ToolUI.h"
+#include "toolutils/toolmenubar.h"
+#include "toolutils/basetoolsystem.h"
+#include "vgui/Cursor.h"
+#include "vgui/ISurface.h"
+#include "tier1/KeyValues.h"
+#include "toolutils/toolmenubar.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+#define MENU_HEIGHT 28
+// Height of the status bar, if the tool installs one
+#define STATUS_HEIGHT 24
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CToolUI::CToolUI( vgui::Panel *pParent, const char *panelName, CBaseToolSystem *pBaseToolSystem ) :
+ BaseClass( pParent, panelName ), m_pClientArea( 0 ), m_pBaseToolSystem( pBaseToolSystem )
+{
+ SetPaintEnabled(false);
+ SetPaintBackgroundEnabled(false);
+ SetPaintBorderEnabled(false);
+
+ int w, h;
+ pParent->GetSize( w, h );
+ SetBounds( 0, 0, w, h );
+
+ m_pMenuBar = m_pBaseToolSystem->CreateMenuBar( m_pBaseToolSystem );
+ m_pMenuBar->SetParent( this );
+ m_pMenuBar->SetSize( w, MENU_HEIGHT );
+ // This can be NULL if no status bar should be included
+ m_pStatusBar = m_pBaseToolSystem->CreateStatusBar( this );
+ m_pStatusBar->SetParent( this );
+
+ m_pClientArea = new vgui::Panel( this, "ClientArea" );
+ m_pClientArea->SetMouseInputEnabled( false );
+ m_pClientArea->SetCursor( vgui::dc_none );
+ m_pClientArea->SetBounds( 0, MENU_HEIGHT, w, h - MENU_HEIGHT );
+}
+
+vgui::Panel *CToolUI::GetClientArea()
+{
+ return m_pClientArea;
+}
+
+
+//-----------------------------------------------------------------------------
+// The tool UI panel should always fill the space...
+//-----------------------------------------------------------------------------
+void CToolUI::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // Make the editor panel fill the space
+ int iWidth, iHeight;
+ vgui::VPANEL parent = GetParent() ? GetParent()->GetVPanel() : vgui::surface()->GetEmbeddedPanel();
+ vgui::ipanel()->GetSize( parent, iWidth, iHeight );
+ SetSize( iWidth, iHeight );
+ int insettop = MENU_HEIGHT;
+ int insetbottom = 0;
+ m_pMenuBar->SetSize( iWidth, insettop );
+ if ( m_pStatusBar )
+ {
+ insetbottom = STATUS_HEIGHT;
+ m_pStatusBar->SetBounds( 0, iHeight - insetbottom, iWidth, insetbottom );
+ }
+ m_pClientArea->SetBounds( 0, insettop, iWidth, iHeight - insettop - insetbottom );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the menu bar
+//-----------------------------------------------------------------------------
+vgui::MenuBar *CToolUI::GetMenuBar()
+{
+ return m_pMenuBar;
+}
+
+vgui::Panel *CToolUI::GetStatusBar()
+{
+ return m_pStatusBar;
+}
+
+//-----------------------------------------------------------------------------
+// Forward commands to systems that have more smarts than I do!
+//-----------------------------------------------------------------------------
+void CToolUI::OnMousePressed( vgui::MouseCode code )
+{
+ // Chain mouse pressed calls to the parent tool workspace
+ CallParentFunction( new KeyValues( "MousePressed", "code", code ) );
+}
+
+void CToolUI::OnCommand( const char *cmd )
+{
+ m_pBaseToolSystem->OnCommand( cmd );
+}
+
+void CToolUI::UpdateMenuBarTitle()
+{
+ CToolFileMenuBar *mb = dynamic_cast< CToolFileMenuBar * >( GetMenuBar() );
+ if ( mb )
+ {
+ char title[ 64 ];
+ m_pBaseToolSystem->ComputeMenuBarTitle( title, sizeof( title ) );
+ mb->SetInfo( title );
+ }
+}
diff --git a/tools/toolutils/ToolUI.h b/tools/toolutils/ToolUI.h
new file mode 100644
index 0000000..8a7a710
--- /dev/null
+++ b/tools/toolutils/ToolUI.h
@@ -0,0 +1,66 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// The tool UI has 4 purposes:
+// 1) Create the menu bar and client area (lies under the menu bar)
+// 2) Forward all mouse messages to the tool workspace so action menus work
+// 3) Forward all commands to the tool system so all smarts can reside there
+// 4) Control the size of the menu bar + the working area
+//=============================================================================
+
+#ifndef TOOLUI_H
+#define TOOLUI_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/panel.h"
+#include "vgui/mousecode.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CBaseToolSystem;
+
+namespace vgui
+{
+ class MenuBar;
+}
+
+//-----------------------------------------------------------------------------
+// The tool UI has 4 purposes:
+// 1) Create the menu bar and client area (lies under the menu bar)
+// 2) Forward all mouse messages to the tool workspace so action menus work
+// 3) Forward all commands to the tool system so all smarts can reside there
+// 4) Control the size of the menu bar + the working area
+//-----------------------------------------------------------------------------
+class CToolUI : public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CToolUI, vgui::Panel );
+
+public:
+ // Constructor
+ CToolUI( vgui::Panel *pParent, const char *pPanelName, CBaseToolSystem *pBaseToolSystem );
+
+ // Overrides of panel methods
+ virtual void PerformLayout();
+ virtual void OnCommand( const char *cmd );
+ virtual void OnMousePressed( vgui::MouseCode code );
+
+ virtual void UpdateMenuBarTitle();
+
+ // Other public methods
+ vgui::MenuBar *GetMenuBar();
+ vgui::Panel *GetClientArea();
+ vgui::Panel *GetStatusBar();
+
+private:
+ vgui::MenuBar *m_pMenuBar;
+ vgui::Panel *m_pStatusBar;
+ vgui::Panel *m_pClientArea;
+ CBaseToolSystem *m_pBaseToolSystem;
+};
+
+
+#endif // TOOLUI_H
diff --git a/tools/toolutils/attributeelementchoicelist.cpp b/tools/toolutils/attributeelementchoicelist.cpp
new file mode 100644
index 0000000..974ac21
--- /dev/null
+++ b/tools/toolutils/attributeelementchoicelist.cpp
@@ -0,0 +1,137 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "toolutils/attributeelementchoicelist.h"
+#include "datamodel/dmelement.h"
+
+
+typedef CUtlRBTree< CDmElement *, int > ElementDict_t;
+
+
+//-----------------------------------------------------------------------------
+// returns the choice string that AddElementsRecursively would have returned
+//-----------------------------------------------------------------------------
+const char *GetChoiceString( CDmElement *pElement )
+{
+ return pElement->GetName();
+}
+
+//-----------------------------------------------------------------------------
+// Recursively adds all elements referred to this element into the list of elements
+//-----------------------------------------------------------------------------
+void AddElementsRecursively_R( CDmElement *pElement, ElementChoiceList_t &list, ElementDict_t &dict, const char *pElementType )
+{
+ if ( !pElement )
+ return;
+
+ if ( dict.Find( pElement ) != dict.InvalidIndex() )
+ return;
+
+ dict.Insert( pElement );
+
+ if ( pElement->IsA( pElementType ) )
+ {
+ int nIndex = list.AddToTail( );
+ ElementChoice_t &entry = list[nIndex];
+ entry.m_pValue = pElement;
+ entry.m_pChoiceString = GetChoiceString( pElement );
+ }
+
+ for ( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
+ {
+ char const *attributeName = pAttribute->GetName( );
+ DmAttributeType_t attrType = pAttribute->GetType( );
+ if ( attrType == AT_ELEMENT )
+ {
+ CDmElement *pChild = pElement->GetValueElement< CDmElement >( attributeName );
+ AddElementsRecursively_R( pChild, list, dict, pElementType );
+ }
+ else if ( attrType == AT_ELEMENT_ARRAY )
+ {
+ const CDmrElementArray<CDmElement> children( pElement, attributeName );
+ uint n = children.Count();
+ for ( uint i = 0; i < n; ++i )
+ {
+ CDmElement *pChild = children[ i ];
+ AddElementsRecursively_R( pChild, list, dict, pElementType );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Recursively adds all elements referred to this element into the list of elements
+//-----------------------------------------------------------------------------
+void AddElementsRecursively_R( CDmElement *pElement, DmeHandleVec_t &list, ElementDict_t &dict, const char *pElementType )
+{
+ if ( !pElement )
+ return;
+
+ if ( dict.Find( pElement ) != dict.InvalidIndex() )
+ return;
+
+ dict.Insert( pElement );
+
+ if ( pElement->IsA( pElementType ) )
+ {
+ int nIndex = list.AddToTail( );
+ list[nIndex] = pElement;
+ }
+
+ for ( CDmAttribute *pAttribute = pElement->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
+ {
+ char const *attributeName = pAttribute->GetName( );
+ DmAttributeType_t attrType = pAttribute->GetType( );
+ if ( attrType == AT_ELEMENT )
+ {
+ CDmElement *pChild = pElement->GetValueElement< CDmElement >( attributeName );
+ AddElementsRecursively_R( pChild, list, dict, pElementType );
+ }
+ else if ( attrType == AT_ELEMENT_ARRAY )
+ {
+ const CDmrElementArray<CDmElement> children( pElement, attributeName );
+ uint n = children.Count();
+ for ( uint i = 0; i < n; ++i )
+ {
+ CDmElement *pChild = children[ i ];
+ AddElementsRecursively_R( pChild, list, dict, pElementType );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Recursively adds all elements referred to this element into the list of elements
+//-----------------------------------------------------------------------------
+void AddElementsRecursively( CDmElement *obj, ElementChoiceList_t &list, const char *pElementType )
+{
+ if ( !pElementType )
+ {
+ pElementType = g_pDataModel->GetString( CDmElement::GetStaticTypeSymbol() );
+ }
+
+ ElementDict_t dict( 0, 0, DefLessFunc( CDmElement * ) );
+ AddElementsRecursively_R( obj, list, dict, pElementType );
+}
+
+
+//-----------------------------------------------------------------------------
+// Recursively adds all elements of the specified type under pElement into the vector
+//-----------------------------------------------------------------------------
+void AddElementsRecursively( CDmElement *pElement, DmeHandleVec_t &list, const char *pElementType )
+{
+ if ( !pElementType )
+ {
+ pElementType = g_pDataModel->GetString( CDmElement::GetStaticTypeSymbol() );
+ }
+
+ ElementDict_t dict( 0, 0, DefLessFunc( CDmElement * ) );
+ AddElementsRecursively_R( pElement, list, dict, pElementType );
+}
diff --git a/tools/toolutils/basepropertiescontainer.cpp b/tools/toolutils/basepropertiescontainer.cpp
new file mode 100644
index 0000000..50891a9
--- /dev/null
+++ b/tools/toolutils/basepropertiescontainer.cpp
@@ -0,0 +1,47 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "toolutils/basepropertiescontainer.h"
+#include "tier1/KeyValues.h"
+
+CBasePropertiesContainer::CBasePropertiesContainer( vgui::Panel *parent, IDmNotify *pNotify, CDmeEditorTypeDictionary *pDict /*=NULL*/ )
+ : BaseClass( parent, pNotify, NULL, true, pDict )
+{
+ SetDropEnabled( true );
+}
+
+bool CBasePropertiesContainer::IsDroppable( CUtlVector< KeyValues * >& msglist )
+{
+ if ( msglist.Count() != 1 )
+ return false;
+
+ KeyValues *data = msglist[ 0 ];
+ CDmElement *ptr = reinterpret_cast< CDmElement * >( g_pDataModel->GetElement( DmElementHandle_t( data->GetInt( "dmeelement", DMELEMENT_HANDLE_INVALID ) ) ) );
+ if ( !ptr )
+ return false;
+
+ if ( ptr == GetObject() )
+ return false;
+
+ return true;
+}
+
+void CBasePropertiesContainer::OnPanelDropped( CUtlVector< KeyValues * >& msglist )
+{
+ if ( msglist.Count() != 1 )
+ return;
+
+ KeyValues *data = msglist[ 0 ];
+ CDmElement *ptr = reinterpret_cast< CDmElement * >( g_pDataModel->GetElement( DmElementHandle_t( data->GetInt( "dmeelement", DMELEMENT_HANDLE_INVALID ) ) ) );
+ if ( !ptr )
+ return;
+
+ // Already browsing
+ if ( ptr == GetObject() )
+ return;
+
+ SetObject( ptr );
+} \ No newline at end of file
diff --git a/tools/toolutils/basestatusbar.cpp b/tools/toolutils/basestatusbar.cpp
new file mode 100644
index 0000000..1fe8add
--- /dev/null
+++ b/tools/toolutils/basestatusbar.cpp
@@ -0,0 +1,151 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "toolutils/basestatusbar.h"
+#include "toolutils/ConsolePage.h"
+#include "vgui_controls/Label.h"
+#include "movieobjects/dmeclip.h"
+#include "tier1/KeyValues.h"
+#include "vgui/IVGui.h"
+#include "toolutils/enginetools_int.h"
+#include "toolframework/ienginetool.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CBaseStatusBar::CBaseStatusBar( vgui::Panel *parent, char const *panelName )
+ : BaseClass( parent, panelName ),
+ m_flLastFPSSnapShot( -1.0f )
+{
+ SetVisible( true );
+ m_pConsole = new CConsolePage( this, true );
+ m_pLabel = new Label( this, "Console", "#BxConsole" );
+ m_pMemory = new Label( this, "Memory", "" );
+ m_pFPS = new Label( this, "FPS", "" );
+ m_pGameTime = new Label( this, "GameTime", "" );
+
+ MakePopup( false );
+
+ UpdateMemoryUsage( 9.999 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Forces console to take up full area except right edge
+// Input : -
+//-----------------------------------------------------------------------------
+void CBaseStatusBar::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int w, h;
+ GetSize( w, h );
+
+ int oldw = w;
+
+ w *= 0.45f;
+
+ int x = 8;
+
+ int cw, ch;
+ m_pLabel->GetContentSize( cw, ch );
+ m_pLabel->SetBounds( x, 4, cw, h - 8 );
+
+ x += cw + 4;
+
+ int consoleWide = w - x - 8;
+
+ m_pConsole->SetBounds( x, 2, consoleWide, h - 4 );
+
+ x += consoleWide + 4;
+
+ int infoW = 85;
+
+ int rightx = oldw - infoW - 10;
+ m_pFPS->SetBounds( rightx, 2, infoW - 2 - 10, h - 8 );
+ rightx -= infoW;
+ m_pGameTime->SetBounds( rightx, 2, infoW - 2, h - 8 );
+ rightx -= infoW;
+ m_pMemory->SetBounds( rightx, 2, infoW - 2, h - 8 );
+}
+
+void CBaseStatusBar::UpdateMemoryUsage( float mbUsed )
+{
+ char mem[ 256 ];
+ Q_snprintf( mem, sizeof( mem ), "[mem: %.2f Mb]", mbUsed );
+ m_pMemory->SetText( mem );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Message map
+//-----------------------------------------------------------------------------
+void CBaseStatusBar::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ // get the borders we need
+ SetBorder(pScheme->GetBorder("ButtonBorder"));
+
+ // get the background color
+ SetBgColor(pScheme->GetColor( "StatusBar.BgColor", GetBgColor() ));
+
+ m_pLabel->SetFont( pScheme->GetFont( "DefaultVerySmall" ) );
+ m_pMemory->SetFont( pScheme->GetFont( "DefaultVerySmall" ) );
+ m_pFPS->SetFont( pScheme->GetFont( "DefaultVerySmall" ) );
+ m_pGameTime->SetFont( pScheme->GetFont( "DefaultVerySmall" ) );
+}
+
+static float GetMemoryUsage();
+
+void CBaseStatusBar::OnThink()
+{
+ BaseClass::OnThink();
+
+ float curtime = enginetools->GetRealTime();
+
+ char gt[ 32 ];
+ Q_snprintf( gt, sizeof( gt ), "[game: %.3f]", enginetools->ServerTime() );
+ m_pGameTime->SetText( gt );
+
+ float elapsed = curtime - m_flLastFPSSnapShot;
+ if ( elapsed < 0.4f )
+ return;
+
+ m_flLastFPSSnapShot = curtime;
+
+ float ft = enginetools->GetRealFrameTime();
+ if ( ft <= 0.0f )
+ {
+ m_pFPS->SetText( "[fps: ??]" );
+ }
+ else
+ {
+ char fps[ 32 ];
+ Q_snprintf( fps, sizeof( fps ), "[fps: %.1f]", 1.0f / ft );
+ m_pFPS->SetText( fps );
+ }
+
+ UpdateMemoryUsage( GetMemoryUsage() );
+}
+
+#include <windows.h>
+#include <psapi.h>
+static float GetMemoryUsage()
+{
+ PROCESS_MEMORY_COUNTERS counters;
+ counters.cb = sizeof( counters );
+
+ if ( GetProcessMemoryInfo( GetCurrentProcess(), &counters, sizeof( counters ) ) )
+ {
+ return (float)counters.WorkingSetSize / ( 1024.0f * 1024.0f );
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/tools/toolutils/miniviewport.cpp b/tools/toolutils/miniviewport.cpp
new file mode 100644
index 0000000..2b74c35
--- /dev/null
+++ b/tools/toolutils/miniviewport.cpp
@@ -0,0 +1,457 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "toolutils/miniviewport.h"
+#include "tier1/utlstring.h"
+#include "vgui/ISurface.h"
+#include "materialsystem/imaterialsystemhardwareconfig.h"
+#include "materialsystem/imaterialsystem.h"
+#include "materialsystem/MaterialSystemUtil.h"
+#include "materialsystem/imesh.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/itexture.h"
+#include "tier1/KeyValues.h"
+#include "toolframework/ienginetool.h"
+#include "toolutils/enginetools_int.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "view_shared.h"
+#include "texture_group_names.h"
+#include "vgui_controls/PropertySheet.h"
+#include "tier2/tier2.h"
+#include <windows.h> // for MultiByteToWideChar
+#include "cdll_int.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+class CMiniViewportEngineRenderArea;
+
+using namespace vgui;
+
+extern IMatSystemSurface *g_pMatSystemSurface;
+
+#define DEFAULT_PREVIEW_WIDTH 1280
+
+//-----------------------------------------------------------------------------
+// Purpose: This is a "frame" which is used to position the engine
+//-----------------------------------------------------------------------------
+class CMiniViewportPropertyPage : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CMiniViewportPropertyPage, vgui::EditablePanel );
+
+public:
+ CMiniViewportPropertyPage( Panel *parent, const char *panelName );
+
+ virtual Color GetBgColor();
+
+ void GetEngineBounds( int& x, int& y, int& w, int& h );
+
+ void RenderFrameBegin();
+
+ CMiniViewportEngineRenderArea *GetViewportArea() { return m_pViewportArea; }
+
+private:
+ virtual void PerformLayout();
+
+ Color m_bgColor;
+
+ CMiniViewportEngineRenderArea *m_pViewportArea;
+};
+
+//-----------------------------------------------------------------------------
+//
+// the actual renderable area
+//
+//-----------------------------------------------------------------------------
+class CMiniViewportEngineRenderArea : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CMiniViewportEngineRenderArea, vgui::EditablePanel );
+
+public:
+ CMiniViewportEngineRenderArea( Panel *parent, const char *panelName );
+ ~CMiniViewportEngineRenderArea();
+
+ virtual void PaintBackground();
+ virtual void GetEngineBounds( int& x, int& y, int& w, int& h );
+ virtual void ApplySchemeSettings( IScheme *pScheme );
+
+ void RenderFrameBegin();
+ void SetOverlayText( const char *pText );
+
+ // Called when the layoff texture needs to be released
+ void ReleaseLayoffTexture();
+
+protected:
+ void InitSceneMaterials();
+ void ShutdownSceneMaterials();
+
+ // Paints the black borders around the engine window
+ void PaintEngineBorders( int x, int y, int w, int h );
+
+ // Paints the engine window itself
+ void PaintEngineWindow( int x, int y, int w, int h );
+
+ // Paints the overlay text
+ void PaintOverlayText( );
+
+ int m_nEngineOutputTexture;
+ vgui::HFont m_OverlayTextFont;
+ CUtlString m_OverlayText;
+
+ CTextureReference m_ScreenBuffer;
+ CMaterialReference m_ScreenMaterial;
+};
+
+
+CMiniViewportEngineRenderArea::CMiniViewportEngineRenderArea( Panel *parent, const char *panelName )
+ : BaseClass( parent, panelName )
+{
+ SetPaintEnabled( false );
+ SetPaintBorderEnabled( false );
+ SetPaintBackgroundEnabled( true );
+
+ m_nEngineOutputTexture = vgui::surface()->CreateNewTextureID();
+}
+
+CMiniViewportEngineRenderArea::~CMiniViewportEngineRenderArea()
+{
+ ShutdownSceneMaterials();
+}
+
+void CMiniViewportEngineRenderArea::RenderFrameBegin()
+{
+ if ( !enginetools->IsInGame() )
+ return;
+
+ InitSceneMaterials();
+
+ CViewSetup playerViewSetup;
+ int x, y, w, h;
+ GetEngineBounds( x, y, w, h );
+ enginetools->GetPlayerView( playerViewSetup, 0, 0, w, h );
+
+ // NOTE: This is a workaround to a nasty problem. Vgui uses stencil
+ // to determing if the panels should occlude each other. The engine
+ // has now started to use stencil for various random effects.
+ // To prevent these different stencil uses from clashing, we will
+ // render the engine prior to vgui painting + cache the result off in
+ //
+ // Make the engine draw the scene
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+ pRenderContext->PushRenderTargetAndViewport( m_ScreenBuffer, 0, 0, w, h );
+
+ // Tell the engine to tell the client to render the view (sans viewmodel)
+ enginetools->SetMainView( playerViewSetup.origin, playerViewSetup.angles );
+ enginetools->RenderView( playerViewSetup, VIEW_CLEAR_COLOR | VIEW_CLEAR_DEPTH, RENDERVIEW_DRAWHUD | RENDERVIEW_DRAWVIEWMODEL );
+
+ // Pop the target
+ pRenderContext->PopRenderTargetAndViewport();
+}
+
+void CMiniViewportEngineRenderArea::InitSceneMaterials()
+{
+ if ( m_ScreenBuffer )
+ return;
+
+ if ( g_pMaterialSystem->IsTextureLoaded( "_rt_LayoffResult" ) )
+ {
+ ITexture *pTexture = g_pMaterialSystem->FindTexture( "_rt_LayoffResult", TEXTURE_GROUP_RENDER_TARGET );
+ m_ScreenBuffer.Init( pTexture );
+ }
+ else
+ {
+ // For now, layoff dimensions match aspect of back buffer
+ int nBackBufferWidth, nBackBufferHeight;
+ g_pMaterialSystem->GetBackBufferDimensions( nBackBufferWidth, nBackBufferHeight );
+ float flAspect = nBackBufferWidth / (float)nBackBufferHeight;
+ int nPreviewWidth = min( DEFAULT_PREVIEW_WIDTH, nBackBufferWidth );
+ int nPreviewHeight = ( int )( nPreviewWidth / flAspect + 0.5f );
+
+ g_pMaterialSystem->BeginRenderTargetAllocation(); // Begin allocating RTs which IFM can scribble into
+
+ // LDR final result of either HDR or LDR rendering
+ m_ScreenBuffer.Init( g_pMaterialSystem->CreateNamedRenderTargetTextureEx2(
+ "_rt_LayoffResult", nPreviewWidth, nPreviewHeight, RT_SIZE_OFFSCREEN,
+ g_pMaterialSystem->GetBackBufferFormat(), MATERIAL_RT_DEPTH_SHARED, TEXTUREFLAGS_BORDER ) );
+
+ g_pMaterialSystem->EndRenderTargetAllocation(); // End allocating RTs which IFM can scribble into
+ }
+
+ KeyValues *pVMTKeyValues = NULL;
+ pVMTKeyValues= new KeyValues( "UnlitGeneric" );
+ pVMTKeyValues->SetString( "$basetexture", m_ScreenBuffer->GetName() );
+ pVMTKeyValues->SetInt( "$nofog", 1 );
+ m_ScreenMaterial.Init( "MiniViewportEngineRenderAreaSceneMaterial", pVMTKeyValues );
+ m_ScreenMaterial->Refresh();
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when the layoff texture needs to be released
+//-----------------------------------------------------------------------------
+void CMiniViewportEngineRenderArea::ReleaseLayoffTexture()
+{
+ m_ScreenBuffer.Shutdown();
+ m_ScreenMaterial.Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// Apply scheme settings
+//-----------------------------------------------------------------------------
+void CMiniViewportEngineRenderArea::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ m_OverlayTextFont = pScheme->GetFont( "DefaultLargeOutline" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMiniViewportEngineRenderArea::ShutdownSceneMaterials()
+{
+ m_ScreenBuffer.Shutdown();
+ m_ScreenMaterial.Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets text to draw over the window
+//-----------------------------------------------------------------------------
+void CMiniViewportEngineRenderArea::SetOverlayText( const char *pText )
+{
+ m_OverlayText = pText;
+}
+
+
+//-----------------------------------------------------------------------------
+// Paints the black borders around the engine window
+//-----------------------------------------------------------------------------
+void CMiniViewportEngineRenderArea::PaintEngineBorders( int x, int y, int w, int h )
+{
+ // Draws black borders around the engine window
+ surface()->DrawSetColor( Color( 0, 0, 0, 255 ) );
+ if ( x != 0 )
+ {
+ surface()->DrawFilledRect( 0, 0, x, h );
+ surface()->DrawFilledRect( x + w, 0, w + 2 * x, h );
+ }
+ else if ( y != 0 )
+ {
+ surface()->DrawFilledRect( 0, 0, w, y );
+ surface()->DrawFilledRect( 0, y + h, w, h + 2 * y );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Paints the overlay text
+//-----------------------------------------------------------------------------
+void CMiniViewportEngineRenderArea::PaintOverlayText( )
+{
+ if ( !m_OverlayText.Length() )
+ return;
+
+ int cw, ch;
+ GetSize( cw, ch );
+
+ int nTextWidth, nTextHeight;
+ int nBufLen = m_OverlayText.Length()+1;
+ wchar_t *pTemp = (wchar_t*)_alloca( nBufLen * sizeof(wchar_t) );
+ ::MultiByteToWideChar( CP_UTF8, 0, m_OverlayText.Get(), -1, pTemp, nBufLen );
+
+ g_pMatSystemSurface->GetTextSize( m_OverlayTextFont, pTemp, nTextWidth, nTextHeight );
+ int lx = (cw - nTextWidth) / 2;
+ if ( lx < 10 )
+ {
+ lx = 10;
+ }
+ int ly = ch - 10 - nTextHeight;
+ g_pMatSystemSurface->DrawColoredTextRect( m_OverlayTextFont,
+ lx, ly, cw - lx, ch - ly,
+ 255, 255, 255, 255, "%s", m_OverlayText.Get() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Paints the engine window itself
+//-----------------------------------------------------------------------------
+void CMiniViewportEngineRenderArea::PaintEngineWindow( int x, int y, int w, int h )
+{
+ if ( !enginetools->IsInGame() )
+ {
+ surface()->DrawSetColor( Color( 127, 127, 200, 63 ) );
+ surface()->DrawFilledRect( x, y, x + w, y + h );
+ }
+ else
+ {
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+
+ g_pMatSystemSurface->DrawSetTextureMaterial( m_nEngineOutputTexture, m_ScreenMaterial );
+ surface()->DrawSetColor( Color( 0, 0, 0, 255 ) );
+
+ int nTexWidth = m_ScreenBuffer->GetActualWidth();
+ int nTexHeight = m_ScreenBuffer->GetActualHeight();
+ float flOOWidth = 1.0f / nTexWidth;
+ float flOOHeight = 1.0f / nTexHeight;
+
+ float s0, s1, t0, t1;
+
+ s0 = ( 0.5f ) * flOOWidth;
+ t0 = ( 0.5f ) * flOOHeight;
+ s1 = ( (float)w - 0.5f ) * flOOWidth;
+ t1 = ( (float)h - 0.5f ) * flOOHeight;
+
+ vgui::surface()->DrawTexturedSubRect( x, y, x+w, y+h, s0, t0, s1, t1 );
+
+ PaintOverlayText();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Paints the background
+//-----------------------------------------------------------------------------
+void CMiniViewportEngineRenderArea::PaintBackground()
+{
+ int x, y, w, h;
+ GetEngineBounds( x, y, w, h );
+ PaintEngineBorders( x, y, w, h );
+ PaintEngineWindow( x, y, w, h );
+}
+
+void CMiniViewportEngineRenderArea::GetEngineBounds( int& x, int& y, int& w, int& h )
+{
+ x = 0;
+ y = 0;
+ GetSize( w, h );
+
+ // Check aspect ratio
+ int sx, sy;
+ surface()->GetScreenSize( sx, sy );
+
+ if ( sy > 0 &&
+ h > 0 )
+ {
+ float screenaspect = (float)sx / (float)sy;
+ float aspect = (float)w / (float)h;
+
+ float ratio = screenaspect / aspect;
+
+ // Screen is wider, need bars at top and bottom
+ if ( ratio > 1.0f )
+ {
+ int usetall = (float)w / screenaspect;
+ y = ( h - usetall ) / 2;
+ h = usetall;
+ }
+ // Screen is narrower, need bars at left/right
+ else
+ {
+ int usewide = (float)h * screenaspect;
+ x = ( w - usewide ) / 2;
+ w = usewide;
+ }
+ }
+}
+
+CMiniViewportPropertyPage::CMiniViewportPropertyPage(Panel *parent, const char *panelName ) :
+ BaseClass( parent, panelName )
+{
+ m_bgColor = Color( 0, 0, 0, 0 );
+
+ m_pViewportArea = new CMiniViewportEngineRenderArea( this, "Engine" );
+}
+
+void CMiniViewportPropertyPage::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int w, h;
+ GetSize( w, h );
+ m_pViewportArea->SetBounds( 0, 0, w, h );
+}
+
+Color CMiniViewportPropertyPage::GetBgColor()
+{
+ return m_bgColor;
+}
+
+
+void CMiniViewportPropertyPage::GetEngineBounds( int& x, int& y, int& w, int& h )
+{
+ m_pViewportArea->GetEngineBounds( x, y, w, h );
+ m_pViewportArea->LocalToScreen( x, y );
+}
+
+void CMiniViewportPropertyPage::RenderFrameBegin()
+{
+ m_pViewportArea->RenderFrameBegin();
+}
+
+CMiniViewport::CMiniViewport( vgui::Panel *parent, bool contextLabel, vgui::IToolWindowFactory *factory /*= 0*/,
+ vgui::Panel *page /*= NULL*/, char const *title /*= NULL*/, bool contextMenu /*= false*/ ) :
+ BaseClass( parent, contextLabel, factory, page, title, contextMenu, false )
+{
+ SetCloseButtonVisible( false );
+
+ GetPropertySheet()->SetDraggableTabs( false );
+
+ // Add the viewport panel
+ m_hPage = new CMiniViewportPropertyPage( this, "ViewportPage" );
+
+ AddPage( m_hPage.Get(), "#ToolMiniViewport", false );
+}
+
+void CMiniViewport::GetViewport( bool& enabled, int& x, int& y, int& w, int& h )
+{
+ enabled = false;
+ x = y = w = h = 0;
+
+ int screenw, screenh;
+ surface()->GetScreenSize( screenw, screenh );
+
+ m_hPage->GetEngineBounds( x, y, w, h );
+
+ y = screenh - ( y + h );
+}
+
+void CMiniViewport::GetEngineBounds( int& x, int& y, int& w, int& h )
+{
+ m_hPage->GetEngineBounds( x, y, w, h );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when the layoff texture needs to be released
+//-----------------------------------------------------------------------------
+void CMiniViewport::ReleaseLayoffTexture()
+{
+ if ( m_hPage.Get() )
+ {
+ m_hPage->GetViewportArea()->ReleaseLayoffTexture();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets text to draw over the window
+//-----------------------------------------------------------------------------
+void CMiniViewport::SetOverlayText( const char *pText )
+{
+ if ( m_hPage.Get() )
+ {
+ m_hPage->GetViewportArea()->SetOverlayText( pText );
+ }
+}
+
+void CMiniViewport::RenderFrameBegin()
+{
+ if ( m_hPage.Get() )
+ {
+ m_hPage->RenderFrameBegin();
+ }
+}
diff --git a/tools/toolutils/recentfilelist.cpp b/tools/toolutils/recentfilelist.cpp
new file mode 100644
index 0000000..d8a436c
--- /dev/null
+++ b/tools/toolutils/recentfilelist.cpp
@@ -0,0 +1,157 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core Movie Maker UI API
+//
+//=============================================================================
+
+#include "toolutils/recentfilelist.h"
+#include "vgui_controls/menu.h"
+#include "iregistry.h"
+#include "tier1/KeyValues.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+
+//-----------------------------------------------------------------------------
+// Adds a file to the list of recent files
+//-----------------------------------------------------------------------------
+void CRecentFileList::Add( const char *pFileName, const char *pFileFormat )
+{
+ RecentFileInfo_t info;
+ info.m_pFileName = pFileName;
+ int idx = m_RecentFiles.Find( info );
+ if ( idx != m_RecentFiles.InvalidIndex() )
+ {
+ // Remove from current slot so it gets added to head (most recent) below...
+ m_RecentFiles.Remove( idx );
+ }
+
+ while ( m_RecentFiles.Count() >= MAX_RECENT_FILES )
+ {
+ // Oldest is at last slot
+ m_RecentFiles.Remove( m_RecentFiles.Count() - 1 );
+ }
+
+ int i = m_RecentFiles.AddToHead( );
+ m_RecentFiles[i].m_pFileName = pFileName;
+ m_RecentFiles[i].m_pFileFormat = pFileFormat;
+}
+
+
+//-----------------------------------------------------------------------------
+// Removes all files from the list
+//-----------------------------------------------------------------------------
+void CRecentFileList::Clear()
+{
+ m_RecentFiles.RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns true if there's no files in the file list
+//-----------------------------------------------------------------------------
+bool CRecentFileList::IsEmpty() const
+{
+ return m_RecentFiles.Count() == 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the file in a particular slot
+//-----------------------------------------------------------------------------
+const char *CRecentFileList::GetFile( int slot ) const
+{
+ if ( slot < 0 || slot >= m_RecentFiles.Count() )
+ return NULL;
+
+ return m_RecentFiles[slot].m_pFileName;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the file in a particular slot
+//-----------------------------------------------------------------------------
+const char *CRecentFileList::GetFileFormat( int slot ) const
+{
+ if ( slot < 0 || slot >= m_RecentFiles.Count() )
+ return NULL;
+
+ return m_RecentFiles[slot].m_pFileFormat;
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads the file list from the registry
+//-----------------------------------------------------------------------------
+void CRecentFileList::LoadFromRegistry( const char *pToolKeyName )
+{
+ Clear();
+
+ // Iterate in reverse order so most recent files goes to top
+ for ( int i = MAX_RECENT_FILES; i >= 0; --i )
+ {
+ char sz[ 128 ];
+ char szType[ 128 ];
+ Q_snprintf( sz, sizeof( sz ), "%s\\history%02i", pToolKeyName, i );
+ Q_snprintf( szType, sizeof( szType ), "%s\\history_fileformat%02i", pToolKeyName, i );
+
+ // NOTE: Can't call registry->ReadString twice in a row!
+ char pFileName[MAX_PATH];
+ Q_strncpy( pFileName, registry->ReadString( sz, "" ), sizeof(pFileName) );
+ if ( pFileName && pFileName[ 0 ] )
+ {
+ const char *valType = registry->ReadString( szType, "" );
+ const char *pFormat = (valType && valType[0]) ? valType : "dmx";
+ Add( pFileName, pFormat );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Saves file list into the registry
+//-----------------------------------------------------------------------------
+void CRecentFileList::SaveToRegistry( const char *pToolKeyName ) const
+{
+ char sz[ 128 ];
+
+ int i, c;
+ c = m_RecentFiles.Count();
+ for ( i = 0 ; i < c; ++i )
+ {
+ Q_snprintf( sz, sizeof( sz ), "%s\\history%02i", pToolKeyName, i );
+ registry->WriteString( sz, m_RecentFiles[i].m_pFileName );
+
+ Q_snprintf( sz, sizeof( sz ), "%s\\history_fileformat%02i", pToolKeyName, i );
+ registry->WriteString( sz, m_RecentFiles[i].m_pFileFormat );
+ }
+
+ // Clear out all other registry settings
+ for ( ; i < MAX_RECENT_FILES; ++i )
+ {
+ Q_snprintf( sz, sizeof( sz ), "%s\\history%02i", pToolKeyName, i );
+ registry->WriteString( sz, "" );
+
+ Q_snprintf( sz, sizeof( sz ), "%s\\history_fileformat%02i", pToolKeyName, i );
+ registry->WriteString( sz, "" );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Adds the list of files to a particular menu
+//-----------------------------------------------------------------------------
+void CRecentFileList::AddToMenu( vgui::Menu *menu, vgui::Panel *pActionTarget, const char *pCommandName ) const
+{
+ int i, c;
+ c = m_RecentFiles.Count();
+ for ( i = 0 ; i < c; ++i )
+ {
+ char sz[ 32 ];
+ Q_snprintf( sz, sizeof( sz ), "%s%02i", pCommandName, i );
+ char const *fn = m_RecentFiles[i].m_pFileName;
+ menu->AddMenuItem( fn, new KeyValues( "Command", "command", sz ), pActionTarget );
+ }
+}
diff --git a/tools/toolutils/savewindowpositions.cpp b/tools/toolutils/savewindowpositions.cpp
new file mode 100644
index 0000000..8447bf0
--- /dev/null
+++ b/tools/toolutils/savewindowpositions.cpp
@@ -0,0 +1,286 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "toolutils/savewindowpositions.h"
+#include "iregistry.h"
+#include "vgui_controls/Panel.h"
+#include "vgui_controls/PHandle.h"
+#include "vgui_controls/ToolWindow.h"
+#include "vgui/ISurface.h"
+#include "vgui_controls/PropertySheet.h"
+#include "tier1/utlsymbol.h"
+#include "tier1/utlbuffer.h"
+#include "tier1/KeyValues.h"
+#include "filesystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: This will save the bounds and the visibility state of UI elements registered during startup
+// FIXME: Preserve Z order?
+//-----------------------------------------------------------------------------
+class CWindowPositionMgr : public IWindowPositionMgr
+{
+public:
+ // Inherited from IWindowPositionMgr
+ virtual void SavePositions( char const *filename, char const *key );
+ virtual bool LoadPositions( char const *filename, Panel *parent, vgui::IToolWindowFactory *factory, char const *key, bool force = false );
+ virtual void RegisterPanel( char const *saveName, Panel *panel, bool contextMenu );
+ virtual void UnregisterPanel( vgui::Panel *panel );
+
+private:
+ struct LoadInfo_t
+ {
+ CUtlSymbol m_Name;
+ PHandle m_hPanel;
+ bool m_bLoaded;
+ bool m_bContextMenu;
+ };
+
+ LoadInfo_t *Find( Panel *panel );
+ LoadInfo_t *Find( char const *panelName );
+
+ CUtlVector< LoadInfo_t > m_Panels;
+};
+
+
+//-----------------------------------------------------------------------------
+// Singleton instance
+//-----------------------------------------------------------------------------
+static CWindowPositionMgr g_WindowPositionMgr;
+IWindowPositionMgr *windowposmgr = &g_WindowPositionMgr;
+
+CWindowPositionMgr::LoadInfo_t *CWindowPositionMgr::Find( Panel *panel )
+{
+ if ( !panel )
+ return NULL;
+
+ int c = m_Panels.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ LoadInfo_t *info = &m_Panels[ i ];
+ if ( info->m_hPanel.Get() == panel )
+ return info;
+ }
+ return NULL;
+}
+
+CWindowPositionMgr::LoadInfo_t *CWindowPositionMgr::Find( char const *panelName )
+{
+ if ( !panelName )
+ return NULL;
+
+ int c = m_Panels.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ LoadInfo_t *info = &m_Panels[ i ];
+ if ( !Q_stricmp( info->m_Name.String(), panelName ) )
+ return info;
+ }
+ return NULL;
+}
+
+static void BufPrint( CUtlBuffer& buf, int level, char const *fmt, ... )
+{
+ char string[ 2048 ];
+ va_list argptr;
+ va_start( argptr, fmt );
+ _vsnprintf( string, sizeof( string ) - 1, fmt, argptr );
+ va_end( argptr );
+ string[ sizeof( string ) - 1 ] = 0;
+
+ while ( --level >= 0 )
+ {
+ buf.Printf( " " );
+ }
+ buf.Printf( "%s", string );
+}
+
+void CWindowPositionMgr::SavePositions( char const *filename, char const *key )
+{
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+ buf.Printf( "%s\n", key );
+ buf.Printf( "{\n" );
+
+ int sw, sh;
+ vgui::surface()->GetScreenSize( sw, sh );
+ float flOOW = (sw != 0.0f) ? 1.0f / (float)sw : 1.0f;
+ float flOOH = (sh != 0.0f) ? 1.0f / (float)sh : 1.0f;
+
+ int c = ToolWindow::GetToolWindowCount();
+
+ for ( int i = 0 ; i < c; ++i )
+ {
+ ToolWindow *tw = ToolWindow::GetToolWindow( i );
+ Assert( tw );
+ if ( !tw )
+ continue;
+
+ BufPrint( buf, 1, "toolwindow\n" );
+ BufPrint( buf, 1, "{\n" );
+
+ // Get panel bounds
+ int x, y, w, h;
+ tw->GetBounds( x, y, w, h );
+
+ float fx = (float)x * flOOW;
+ float fy = (float)y * flOOH;
+ float fw = (float)w * flOOW;
+ float fh = (float)h * flOOH;
+ BufPrint( buf, 2, "bounds \"%.10f %.10f %.10f %.10f\"\n", fx, fy, fw, fh );
+
+ // Now iterate the actual contained panels
+ PropertySheet *sheet = tw->GetPropertySheet();
+ Assert( sheet );
+ if ( sheet )
+ {
+ int subCount = sheet->GetNumPages();
+ Assert( subCount > 0 );
+ if ( subCount > 0 )
+ {
+ BufPrint( buf, 2, "windows\n" );
+ BufPrint( buf, 2, "{\n" );
+
+ for ( int s = 0 ; s < subCount; ++s )
+ {
+ Panel *subPanel = sheet->GetPage( s );
+ if ( !subPanel )
+ continue;
+
+ LoadInfo_t *info = Find( subPanel );
+ if ( !info )
+ continue;
+
+ BufPrint( buf, 3, "panel \"%s\"\n", info->m_Name.String() );
+ }
+
+ BufPrint( buf, 2, "}\n" );
+ }
+ }
+
+ BufPrint( buf, 1, "}\n" );
+ }
+
+ buf.Printf( "}\n" );
+
+ if ( g_pFullFileSystem->FileExists( filename, "DEFAULT_WRITE_PATH" ) &&
+ !g_pFullFileSystem->IsFileWritable( filename, "DEFAULT_WRITE_PATH" ) )
+ {
+ Warning( "IFM window layout file '%s' is read-only!!!\n", filename );
+ }
+
+ FileHandle_t h = g_pFullFileSystem->Open( filename, "wb", "DEFAULT_WRITE_PATH" );
+ if ( FILESYSTEM_INVALID_HANDLE != h )
+ {
+ g_pFullFileSystem->Write( buf.Base(), buf.TellPut(), h );
+ g_pFullFileSystem->Close( h );
+ }
+}
+
+bool CWindowPositionMgr::LoadPositions( char const *filename, vgui::Panel *parent, vgui::IToolWindowFactory *factory, char const *key, bool force /*=false*/ )
+{
+ bool success = false;
+
+ int sw, sh;
+ vgui::surface()->GetScreenSize( sw, sh );
+
+ KeyValues *kv = new KeyValues( key );
+ if ( kv->LoadFromFile( g_pFullFileSystem, filename, "GAME" ) )
+ {
+ // Walk through tools
+ for ( KeyValues *tw = kv->GetFirstSubKey(); tw != NULL; tw = tw->GetNextKey() )
+ {
+ if ( Q_stricmp( tw->GetName(), "toolwindow" ) )
+ continue;
+
+ // read bounds
+ float fx, fy, fw, fh;
+ int x, y, w, h;
+ char const *bounds = tw->GetString( "bounds", "" );
+ if ( !bounds || !bounds[ 0 ] )
+ continue;
+
+ if ( 4 != sscanf( bounds, "%f %f %f %f", &fx, &fy, &fw, &fh ) )
+ continue;
+
+ x = (int)( sw * fx + 0.5f );
+ y = (int)( sh * fy + 0.5f );
+ w = (int)( sw * fw + 0.5f );
+ h = (int)( sh * fh + 0.5f );
+
+ w = clamp( w, 0, sw );
+ h = clamp( h, 0, sh );
+
+ // Now load pages
+ KeyValues *pages = tw->FindKey( "windows", false );
+ if ( !pages )
+ continue;
+
+ ToolWindow *newTool = factory->InstanceToolWindow( parent, true, NULL, NULL, false );
+ newTool->SetBounds( x, y, w, h );
+
+ for ( KeyValues *page = pages->GetFirstSubKey(); page != NULL; page = page->GetNextKey() )
+ {
+ if ( Q_stricmp( page->GetName(), "panel" ) )
+ continue;
+
+ char const *pageName = page->GetString();
+ if ( !pageName || !pageName[ 0 ] )
+ continue;
+
+ LoadInfo_t *info = Find( pageName );
+ if ( !info )
+ continue;
+
+ newTool->AddPage( info->m_hPanel.Get(), info->m_Name.String(), info->m_bContextMenu );
+ success = true;
+ }
+
+ // If we didn't successfully create something, delete the tool
+ if ( !success )
+ {
+ delete newTool;
+ }
+ }
+ }
+ kv->deleteThis();
+
+ return success;
+}
+
+void CWindowPositionMgr::RegisterPanel( char const *saveName, Panel *panel, bool contextMenu )
+{
+ char const *panelName = panel->GetName();
+ if ( !panelName || !panelName[ 0 ] )
+ {
+ Warning( "CWindowPositionMgr::RegisterPanel: Panel has NULL or blank name!!!\n" );
+ return;
+ }
+
+ LoadInfo_t info;
+ info.m_hPanel = panel;
+ info.m_Name = saveName;
+ info.m_bLoaded = false;
+ info.m_bContextMenu = contextMenu;
+
+ m_Panels.AddToTail( info );
+}
+
+void CWindowPositionMgr::UnregisterPanel( vgui::Panel *panel )
+{
+ int c = m_Panels.Count();
+ for ( int i = c - 1; i >= 0; --i )
+ {
+ if ( m_Panels[ i ].m_hPanel.Get() != panel )
+ continue;
+
+ m_Panels.Remove( i );
+ break;
+ }
+}
diff --git a/tools/toolutils/tool_main.cpp b/tools/toolutils/tool_main.cpp
new file mode 100644
index 0000000..3895f22
--- /dev/null
+++ b/tools/toolutils/tool_main.cpp
@@ -0,0 +1,233 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "tier1/utlvector.h"
+#include "tier1/convar.h"
+#include "icvar.h"
+#include "toolframework/itoolsystem.h"
+#include "toolframework/itooldictionary.h"
+#include "toolframework/ienginetool.h"
+#include "toolutils/enginetools_int.h"
+#include "ienginevgui.h"
+#include "icvar.h"
+#include "toolutils/vgui_tools.h"
+#include "mathlib/mathlib.h"
+#include "iregistry.h"
+#include "datamodel/idatamodel.h"
+#include "filesystem.h"
+#include "p4lib/ip4.h"
+#include "engine/ivdebugoverlay.h"
+#include "tier3/tier3dm.h"
+#include "datamodel/dmelementfactoryhelper.h"
+#include "dmserializers/idmserializers.h"
+
+//-----------------------------------------------------------------------------
+// Singleton interfaces
+//-----------------------------------------------------------------------------
+IEngineTool *enginetools = NULL;
+IEngineVGui *enginevgui = NULL;
+IFileSystem *g_pFileSystem = NULL;
+IVDebugOverlay *debugoverlay = NULL;
+
+
+//-----------------------------------------------------------------------------
+// Assumed to be implemented within the specific tool DLL
+//-----------------------------------------------------------------------------
+bool ConnectTools( CreateInterfaceFn factory );
+void CreateTools( );
+void DisconnectTools( );
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VGUI_CreateToolRootPanel( void )
+{
+ // Just using PANEL_GAMEDLL in HL2 right now
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VGUI_DestroyToolRootPanel( void )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Global accessors for root tool panels
+//-----------------------------------------------------------------------------
+vgui::VPANEL VGui_GetToolRootPanel( void )
+{
+ vgui::VPANEL root = enginevgui->GetPanel( PANEL_GAMEDLL );
+ return root;
+}
+
+vgui::VPANEL VGui_GetRootPanel( void )
+{
+ vgui::VPANEL root = enginevgui->GetPanel( PANEL_ROOT );
+ return root;
+}
+
+
+//-----------------------------------------------------------------------------
+// Implementation of IToolDictionary
+//-----------------------------------------------------------------------------
+class CToolDictionary : public CTier3DmAppSystem< IToolDictionary >
+{
+ typedef CTier3DmAppSystem< IToolDictionary > BaseClass;
+
+public:
+ CToolDictionary();
+
+ // Inherited from IAppSystem
+ virtual bool Connect( CreateInterfaceFn factory );
+ virtual void Disconnect();
+ virtual void *QueryInterface( const char *pInterfaceName );
+ virtual InitReturnVal_t Init();
+ virtual void Shutdown();
+
+ // Inherited from IToolDictionary
+ virtual void CreateTools();
+ virtual int GetToolCount() const;
+ virtual IToolSystem *GetTool( int index );
+
+public:
+ void RegisterTool( IToolSystem *tool );
+
+private:
+ CUtlVector< IToolSystem * > m_Tools;
+};
+
+
+//-----------------------------------------------------------------------------
+// Singleton interface for tools
+//-----------------------------------------------------------------------------
+static CToolDictionary g_ToolDictionary;
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CToolDictionary, IToolDictionary, VTOOLDICTIONARY_INTERFACE_VERSION, g_ToolDictionary );
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CToolDictionary::CToolDictionary()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from IAppSystem
+//-----------------------------------------------------------------------------
+bool CToolDictionary::Connect( CreateInterfaceFn factory )
+{
+ if ( !BaseClass::Connect( factory ) )
+ return false;
+
+ // FIXME: This interface pointer is taken care of in tier2 + tier1
+ g_pFileSystem = g_pFullFileSystem;
+
+ enginevgui = ( IEngineVGui * )factory( VENGINE_VGUI_VERSION, NULL );
+ enginetools = ( IEngineTool * )factory( VENGINETOOL_INTERFACE_VERSION, NULL );
+ debugoverlay = ( IVDebugOverlay * )factory( VDEBUG_OVERLAY_INTERFACE_VERSION, NULL );
+
+ if ( !enginevgui || !debugoverlay || !g_pCVar || !enginetools || !g_pFileSystem )
+ return false;
+
+ if ( !VGui_Startup( factory ) )
+ return false;
+
+ return ConnectTools( factory );
+}
+
+void CToolDictionary::Disconnect()
+{
+ DisconnectTools();
+ enginevgui = NULL;
+ enginetools = NULL;
+ debugoverlay = NULL;
+ g_pFileSystem = NULL;
+
+ BaseClass::Disconnect( );
+}
+
+void *CToolDictionary::QueryInterface( const char *pInterfaceName )
+{
+ if ( !V_strcmp( pInterfaceName, VTOOLDICTIONARY_INTERFACE_VERSION ) )
+ return (IToolDictionary*)this;
+
+ return NULL;
+}
+
+InitReturnVal_t CToolDictionary::Init()
+{
+ InitReturnVal_t nRetVal = BaseClass::Init();
+ if ( nRetVal != INIT_OK )
+ return nRetVal;
+
+ MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f );
+
+ // Init registry
+ if ( !registry->Init( "Source\\Tools" ) )
+ {
+ Warning( "registry->Init failed\n" );
+ return INIT_FAILED;
+ }
+
+ // Re-enable this and VGui_Shutdown if we create root tool panels
+// VGui_PostInit();
+
+ return INIT_OK;
+}
+
+void CToolDictionary::Shutdown()
+{
+ // Re-enable this and VGui_PostInit if we create root tool panels
+ VGui_Shutdown();
+
+ registry->Shutdown();
+
+ BaseClass::Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// Implementation of IToolDictionary methods
+//-----------------------------------------------------------------------------
+void CToolDictionary::CreateTools()
+{
+ ::CreateTools( );
+}
+
+int CToolDictionary::GetToolCount() const
+{
+ return m_Tools.Count();
+}
+
+IToolSystem *CToolDictionary::GetTool( int index )
+{
+ if ( index < 0 || index >= m_Tools.Count() )
+ {
+ return NULL;
+ }
+ return m_Tools[ index ];
+}
+
+void CToolDictionary::RegisterTool( IToolSystem *tool )
+{
+ m_Tools.AddToTail( tool );
+}
+
+
+//-----------------------------------------------------------------------------
+// Allows tools to install themselves into the dictionary
+//-----------------------------------------------------------------------------
+void RegisterTool( IToolSystem *tool )
+{
+ g_ToolDictionary.RegisterTool( tool );
+}
+
+
diff --git a/tools/toolutils/tooleditmenubutton.cpp b/tools/toolutils/tooleditmenubutton.cpp
new file mode 100644
index 0000000..99e64a3
--- /dev/null
+++ b/tools/toolutils/tooleditmenubutton.cpp
@@ -0,0 +1,131 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Standard edit menu for tools
+//
+//=============================================================================
+
+#include "toolutils/tooleditmenubutton.h"
+#include "toolutils/toolmenubutton.h"
+#include "tier1/KeyValues.h"
+#include "toolutils/enginetools_int.h"
+#include "datamodel/idatamodel.h"
+#include "vgui_controls/menu.h"
+#include "vgui/ilocalize.h"
+#include "tier2/tier2.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+//
+// The Edit menu
+//
+//-----------------------------------------------------------------------------
+class CToolEditMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CToolEditMenuButton, CToolMenuButton );
+public:
+ CToolEditMenuButton( vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu( vgui::Menu *menu );
+};
+
+
+//-----------------------------------------------------------------------------
+// Global function to create the file menu
+//-----------------------------------------------------------------------------
+CToolMenuButton* CreateToolEditMenuButton( vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionTarget )
+{
+ return new CToolEditMenuButton( parent, panelName, text, pActionTarget );
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CToolEditMenuButton::CToolEditMenuButton( vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ AddMenuItem( "undo", "#ToolEditUndo", new KeyValues ( "Command", "command", "OnUndo" ), pActionSignalTarget, NULL, "undo" );
+ AddMenuItem( "redo", "#ToolEditRedo", new KeyValues ( "Command", "command", "OnRedo" ), pActionSignalTarget, NULL, "redo" );
+ AddSeparator();
+ AddMenuItem( "describe", "#ToolEditDescribeUndo", new KeyValues ( "Command", "command", "OnDescribeUndo" ), pActionSignalTarget);
+ AddMenuItem( "wipeundo", "#ToolEditWipeUndo", new KeyValues ( "Command", "command", "OnWipeUndo" ), pActionSignalTarget);
+ AddSeparator();
+ AddMenuItem( "editkeybindings", "#BxEditKeyBindings", new KeyValues( "OnEditKeyBindings" ), pActionSignalTarget, NULL, "editkeybindings" );
+
+ SetMenu(m_pMenu);
+}
+
+void CToolEditMenuButton::OnShowMenu( vgui::Menu *menu )
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ char sz[ 512 ];
+
+ int id;
+ id = m_Items.Find( "undo" );
+ if ( g_pDataModel->CanUndo() )
+ {
+ m_pMenu->SetItemEnabled( id, true );
+
+ wchar_t *fmt = g_pVGuiLocalize->Find( "ToolEditUndoStr" );
+ if ( fmt )
+ {
+ wchar_t desc[ 256 ];
+ g_pVGuiLocalize->ConvertANSIToUnicode( g_pDataModel->GetUndoDesc(), desc, sizeof( desc ) );
+
+ wchar_t buf[ 512 ];
+ g_pVGuiLocalize->ConstructString( buf, sizeof( buf ), fmt, 1, desc );
+
+ m_pMenu->UpdateMenuItem( id, buf, new KeyValues( "Command", "command", "OnUndo" ) );
+ }
+ else
+ {
+ m_pMenu->UpdateMenuItem( id, "#ToolEditUndo", new KeyValues( "Command", "command", "OnUndo" ) );
+ }
+ }
+ else
+ {
+ m_pMenu->SetItemEnabled( id, false );
+ m_pMenu->UpdateMenuItem( id, "#ToolEditUndo", new KeyValues( "Command", "command", "OnUndo" ) );
+ }
+
+ id = m_Items.Find( "redo" );
+ if ( g_pDataModel->CanRedo() )
+ {
+ m_pMenu->SetItemEnabled( id, true );
+
+ wchar_t *fmt = g_pVGuiLocalize->Find( "ToolEditRedoStr" );
+ if ( fmt )
+ {
+ wchar_t desc[ 256 ];
+ g_pVGuiLocalize->ConvertANSIToUnicode( g_pDataModel->GetRedoDesc(), desc, sizeof( desc ) );
+
+ wchar_t buf[ 512 ];
+ g_pVGuiLocalize->ConstructString( buf, sizeof( buf ), fmt, 1, desc );
+
+ m_pMenu->UpdateMenuItem( id, buf, new KeyValues( "Command", "command", "OnRedo" ) );
+ }
+ else
+ {
+ m_pMenu->UpdateMenuItem( id, sz, new KeyValues( "Command", "command", "OnRedo" ) );
+ }
+ }
+ else
+ {
+ m_pMenu->SetItemEnabled( id, false );
+ m_pMenu->UpdateMenuItem( id, "#ToolEditRedo", new KeyValues( "Command", "command", "OnRedo" ) );
+ }
+
+ id = m_Items.Find( "describe" );
+ if ( g_pDataModel->CanUndo() )
+ {
+ m_pMenu->SetItemEnabled( id, true );
+ }
+ else
+ {
+ m_pMenu->SetItemEnabled( id, false );
+ }
+}
diff --git a/tools/toolutils/toolmenubar.cpp b/tools/toolutils/toolmenubar.cpp
new file mode 100644
index 0000000..fb02a35
--- /dev/null
+++ b/tools/toolutils/toolmenubar.cpp
@@ -0,0 +1,132 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core Movie Maker UI API
+//
+//=============================================================================
+
+#include "toolutils/toolmenubar.h"
+#include "vgui_controls/Label.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+//
+// Version that only has tool name and info
+//
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CToolMenuBar::CToolMenuBar( CBaseToolSystem *pParent, const char *pPanelName ) :
+ BaseClass( (Panel *)pParent, pPanelName ),
+ m_pToolSystem( pParent )
+{
+ m_pInfo = new Label( this, "Info", "" );
+ m_pToolName = new Label( this, "ToolName", "" );
+}
+
+CBaseToolSystem *CToolMenuBar::GetToolSystem()
+{
+ return m_pToolSystem;
+}
+
+//-----------------------------------------------------------------------------
+// Sets the tool bar's name
+//-----------------------------------------------------------------------------
+void CToolMenuBar::SetToolName( const char *pName )
+{
+ m_pToolName->SetText( pName );
+ InvalidateLayout();
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the tool bar info
+//-----------------------------------------------------------------------------
+void CToolMenuBar::SetInfo( const char *pInfo )
+{
+ m_pInfo->SetText( pInfo );
+ InvalidateLayout();
+}
+
+
+//-----------------------------------------------------------------------------
+// Lays out the menu bar
+//-----------------------------------------------------------------------------
+void CToolMenuBar::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int w, h;
+ GetSize( w, h );
+
+ int cw, ch;
+ m_pInfo->GetContentSize( cw, ch );
+
+ int right = w - cw - 20;
+ m_pInfo->SetBounds( right, 0, cw, h );
+
+ m_pToolName->GetContentSize( cw, ch );
+ m_pToolName->SetBounds( right - cw - 5, 0, cw, h );
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Version that only has tool name, info, and file name
+//
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CToolFileMenuBar::CToolFileMenuBar( CBaseToolSystem *parent, const char *panelName ) :
+ BaseClass( parent, panelName )
+{
+ m_pFileName = new Label( this, "FileName", "" );
+}
+
+
+void CToolFileMenuBar::SetFileName( char const *name )
+{
+ m_pFileName->SetText( name );
+ InvalidateLayout();
+}
+
+
+//-----------------------------------------------------------------------------
+// Performs layout
+//-----------------------------------------------------------------------------
+void CToolFileMenuBar::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int w, h;
+ GetSize( w, h );
+
+ int cw, ch;
+ m_pInfo->GetContentSize( cw, ch );
+
+ int right = w - cw - 20;
+
+ m_pToolName->GetContentSize( cw, ch );
+
+ int barx, bary;
+ GetContentSize( barx, bary );
+
+ int faredge = right - cw - 5- 2;
+ int nearedge = barx + 2;
+
+ int mid = ( nearedge + faredge ) * 0.5f;
+
+ m_pFileName->GetContentSize( cw, ch );
+ m_pFileName->SetBounds( mid - cw * 0.5f, 0, cw, h );
+}
diff --git a/tools/toolutils/toolutils.vpc b/tools/toolutils/toolutils.vpc
new file mode 100644
index 0000000..6d692cb
--- /dev/null
+++ b/tools/toolutils/toolutils.vpc
@@ -0,0 +1,54 @@
+//-----------------------------------------------------------------------------
+// TOOLUTILS.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Include "$SRCDIR\vpc_scripts\source_lib_base.vpc"
+
+$Project "Toolutils"
+{
+ $Folder "Source Files"
+ {
+ $File "attributeelementchoicelist.cpp"
+ $File "basepropertiescontainer.cpp"
+ $File "basestatusbar.cpp"
+ $File "BaseToolSystem.cpp"
+ $File "ConsolePage.cpp"
+ $File "miniviewport.cpp"
+ $File "recentfilelist.cpp"
+ $File "savewindowpositions.cpp"
+ $File "tool_main.cpp"
+ $File "tooleditmenubutton.cpp"
+ $File "ToolFileMenuButton.cpp"
+ $File "ToolHelpMenuButton.cpp"
+ $File "toolmenubar.cpp"
+ $File "ToolMenuButton.cpp"
+ $File "ToolSwitchMenuButton.cpp"
+ $File "ToolUI.cpp"
+ $File "vgui_tools.cpp"
+ }
+
+ $Folder "Header Files"
+ {
+ $File "$SRCDIR\public\toolutils\AttributeElementChoiceList.h"
+ $File "$SRCDIR\public\toolutils\basepropertiescontainer.h"
+ $File "$SRCDIR\public\toolutils\basestatusbar.h"
+ $File "$SRCDIR\public\toolutils\BaseToolSystem.h"
+ $File "$SRCDIR\public\toolutils\DmeMdlRenderable.h"
+ $File "$SRCDIR\public\toolutils\DmeRenderable.h"
+ $File "$SRCDIR\public\toolutils\enginetools_int.h"
+ $File "$SRCDIR\public\toolutils\miniviewport.h"
+ $File "$SRCDIR\public\toolutils\recentfilelist.h"
+ $File "$SRCDIR\public\toolutils\savewindowpositions.h"
+ $File "$SRCDIR\public\toolutils\ToolEditMenuButton.h"
+ $File "$SRCDIR\public\toolutils\ToolFileMenuButton.h"
+ $File "$SRCDIR\public\toolutils\ToolHelpMenuButton.h"
+ $File "$SRCDIR\public\toolutils\toolmenubar.h"
+ $File "$SRCDIR\public\toolutils\ToolMenuButton.h"
+ $File "$SRCDIR\public\toolutils\ToolSwitchMenuButton.h"
+ $File "ToolUI.h"
+ $File "$SRCDIR\public\toolutils\vgui_tools.h"
+ }
+}
diff --git a/tools/toolutils/vgui_tools.cpp b/tools/toolutils/vgui_tools.cpp
new file mode 100644
index 0000000..f60c1e5
--- /dev/null
+++ b/tools/toolutils/vgui_tools.cpp
@@ -0,0 +1,67 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================
+
+#include "toolutils/vgui_tools.h"
+#include "ienginevgui.h"
+#include <vgui/ISurface.h>
+#include <vgui/IVGui.h>
+#include <vgui/IInput.h>
+#include "tier0/vprof.h"
+#include <vgui_controls/Panel.h>
+#include <KeyValues.h>
+#include <dme_controls/dmeControls.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : appSystemFactory -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool VGui_Startup( CreateInterfaceFn appSystemFactory )
+{
+ // All of the various tools .dlls expose GetVGuiControlsModuleName() to us to make sure we don't have communication across .dlls
+ if ( !vgui::VGui_InitDmeInterfacesList( GetVGuiControlsModuleName(), &appSystemFactory, 1 ) )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool VGui_PostInit()
+{
+ // Create any root panels for .dll
+ VGUI_CreateToolRootPanel();
+
+ // Make sure we have a panel
+ VPANEL root = VGui_GetToolRootPanel();
+ if ( !root )
+ {
+ return false;
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+void VGui_Shutdown()
+{
+ VGUI_DestroyToolRootPanel();
+
+ // Make sure anything "marked for deletion"
+ // actually gets deleted before this dll goes away
+ vgui::ivgui()->RunFrame();
+}
diff --git a/tools/vcdblock/dmevmfentity.cpp b/tools/vcdblock/dmevmfentity.cpp
new file mode 100644
index 0000000..0432634
--- /dev/null
+++ b/tools/vcdblock/dmevmfentity.cpp
@@ -0,0 +1,664 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "DmeVMFEntity.h"
+#include "datamodel/dmelementfactoryhelper.h"
+#include "toolframework/itoolentity.h"
+#include "materialsystem/imesh.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialsystem.h"
+#include "engine/iclientleafsystem.h"
+#include "toolutils/enginetools_int.h"
+#include "vcdblocktool.h"
+#include "tier1/KeyValues.h"
+
+// for tracing
+#include "cmodel.h"
+#include "engine/ienginetrace.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+#define SPHERE_RADIUS 16
+
+//-----------------------------------------------------------------------------
+// Expose this class to the scene database
+//-----------------------------------------------------------------------------
+IMPLEMENT_ELEMENT_FACTORY( DmeVMFEntity, CDmeVMFEntity );
+
+
+//-----------------------------------------------------------------------------
+// Used to store the next unique entity id;
+//-----------------------------------------------------------------------------
+int CDmeVMFEntity::s_nNextEntityId;
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::OnConstruction()
+{
+ m_ClassName.Init( this, "classname", FATTRIB_HAS_CALLBACK );
+ m_TargetName.Init( this, "targetname" );
+ m_bIsPlaceholder.InitAndSet( this, "_placeholder", false, FATTRIB_DONTSAVE );
+ m_vecLocalOrigin.Init( this, "origin" );
+ m_vecLocalAngles.Init( this, "angles" );
+ m_bIsDeleted.Init( this, "deleted" );
+
+ if ( m_Name.Length() == 0 )
+ {
+ // Assign a unique ID to the name
+ char pNameString[128];
+ Q_snprintf( pNameString, sizeof(pNameString), "%d", GetNextEntityId() );
+ m_Name = pNameString;
+ }
+
+ // See if we need to bump the unique id up
+ int nEntityId = GetEntityId();
+ if ( s_nNextEntityId <= nEntityId )
+ {
+ s_nNextEntityId = nEntityId + 1;
+ }
+
+ // Get called back when the name changes
+ m_Name.GetAttribute()->AddFlag( FATTRIB_HAS_CALLBACK );
+
+ // Used to make sure these aren't saved if they aren't changed
+ //m_TargetName.GetAttribute()->AddFlag( FATTRIB_DONTSAVE | FATTRIB_HAS_CALLBACK );
+ //m_vecLocalAngles.GetAttribute()->AddFlag( FATTRIB_DONTSAVE | FATTRIB_HAS_CALLBACK );
+
+ m_bIsDirty = false;
+ m_bInfoTarget = false;
+ m_hEngineEntity = HTOOLHANDLE_INVALID;
+
+ m_Wireframe.Init( "debug/debugwireframevertexcolor", "editor" );
+
+ // FIXME: Need to abstract out rendering into a separate class
+ // based on information parsed from the FGD
+ KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
+ pVMTKeyValues->SetString( "$basetexture", "editor/info_target" );
+ pVMTKeyValues->SetInt( "$nocull", 1 );
+ pVMTKeyValues->SetInt( "$vertexcolor", 1 );
+ pVMTKeyValues->SetInt( "$vertexalpha", 1 );
+ pVMTKeyValues->SetInt( "$no_fullbright", 1 );
+ pVMTKeyValues->SetInt( "$translucent", 1 );
+ m_InfoTargetSprite.Init( "__vcdblock_info_target", pVMTKeyValues );
+
+ pVMTKeyValues = new KeyValues( "UnlitGeneric" );
+ pVMTKeyValues->SetInt( "$nocull", 1 );
+ pVMTKeyValues->SetString( "$color", "{64 64 64}" );
+ pVMTKeyValues->SetInt( "$vertexalpha", 1 );
+ pVMTKeyValues->SetInt( "$no_fullbright", 1 );
+ pVMTKeyValues->SetInt( "$additive", 1 );
+ m_SelectedInfoTarget.Init( "__selected_vcdblock_info_target", pVMTKeyValues );
+}
+
+void CDmeVMFEntity::OnDestruction()
+{
+ // Unhook it from the engine
+ AttachToEngineEntity( false );
+ m_Wireframe.Shutdown();
+ m_SelectedInfoTarget.Shutdown();
+ m_InfoTargetSprite.Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// Called whem attributes change
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::OnAttributeChanged( CDmAttribute *pAttribute )
+{
+ BaseClass::OnAttributeChanged( pAttribute );
+
+ // Once these have changed, then save them out, and don't bother calling back
+ if ( pAttribute == m_TargetName.GetAttribute() ||
+ pAttribute == m_vecLocalAngles.GetAttribute() )
+ {
+ pAttribute->RemoveFlag( FATTRIB_DONTSAVE | FATTRIB_HAS_CALLBACK );
+ return;
+ }
+
+ if ( pAttribute == m_ClassName.GetAttribute() )
+ {
+ m_bInfoTarget = !Q_strncmp( m_ClassName, "info_target", 11 );
+
+ // FIXME: Change the model based on the current class
+ SetModelName( NULL );
+ return;
+ }
+
+ // Make sure we have unique ids for all entities
+ if ( pAttribute == m_Name.GetAttribute() )
+ {
+ int nEntityId = GetEntityId();
+ if ( s_nNextEntityId <= nEntityId )
+ {
+ s_nNextEntityId = nEntityId + 1;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the entity ID
+//-----------------------------------------------------------------------------
+int CDmeVMFEntity::GetEntityId() const
+{
+ return atoi( GetName() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the next available entity id
+//-----------------------------------------------------------------------------
+int CDmeVMFEntity::GetNextEntityId()
+{
+ return s_nNextEntityId;
+}
+
+void CDmeVMFEntity::SetNextEntityId( int nEntityId )
+{
+ s_nNextEntityId = nEntityId;
+}
+
+
+//-----------------------------------------------------------------------------
+// Mark the entity as being dirty
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::MarkDirty( bool bDirty )
+{
+ m_bIsDirty = bDirty;
+
+ // FIXME: this is doing two operations!!
+ CopyToServer();
+}
+
+
+//-----------------------------------------------------------------------------
+// Is the renderable transparent?
+//-----------------------------------------------------------------------------
+bool CDmeVMFEntity::IsTransparent( void )
+{
+ return m_bIsDirty || m_bInfoTarget || BaseClass::IsTransparent();
+}
+
+
+//-----------------------------------------------------------------------------
+// Entity Key iteration
+//-----------------------------------------------------------------------------
+bool CDmeVMFEntity::IsEntityKey( CDmAttribute *pEntityKey )
+{
+ return pEntityKey->IsFlagSet( FATTRIB_USERDEFINED );
+}
+
+CDmAttribute *CDmeVMFEntity::FirstEntityKey()
+{
+ for ( CDmAttribute *pAttribute = FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
+ {
+ if ( IsEntityKey( pAttribute ) )
+ return pAttribute;
+ }
+ return NULL;
+}
+
+CDmAttribute *CDmeVMFEntity::NextEntityKey( CDmAttribute *pEntityKey )
+{
+ if ( !pEntityKey )
+ return NULL;
+
+ for ( CDmAttribute *pAttribute = pEntityKey->NextAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
+ {
+ if ( IsEntityKey( pAttribute ) )
+ return pAttribute;
+ }
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Attach/detach from an engine entity with the same editor index
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::AttachToEngineEntity( HTOOLHANDLE hToolHandle )
+{
+ if ( m_hEngineEntity != HTOOLHANDLE_INVALID )
+ {
+ clienttools->SetEnabled( m_hEngineEntity, true );
+ }
+ m_hEngineEntity = hToolHandle;
+ if ( m_hEngineEntity != HTOOLHANDLE_INVALID )
+ {
+ clienttools->SetEnabled( m_hEngineEntity, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Position and bounds for the model
+//-----------------------------------------------------------------------------
+const Vector &CDmeVMFEntity::GetRenderOrigin( void )
+{
+ return m_vecLocalOrigin;
+}
+
+const QAngle &CDmeVMFEntity::GetRenderAngles( void )
+{
+ return *(QAngle *)(&m_vecLocalAngles);
+}
+
+void CDmeVMFEntity::GetRenderBounds( Vector& mins, Vector& maxs )
+{
+ if ( !m_bInfoTarget )
+ {
+ BaseClass::GetRenderBounds( mins, maxs );
+ return;
+ }
+
+ mins.Init( -SPHERE_RADIUS, -SPHERE_RADIUS, -SPHERE_RADIUS );
+ maxs.Init( SPHERE_RADIUS, SPHERE_RADIUS, SPHERE_RADIUS );
+}
+
+
+//-----------------------------------------------------------------------------
+// Update renderable position
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::SetRenderOrigin( const Vector &vecOrigin )
+{
+ m_vecLocalOrigin = vecOrigin;
+ clienttools->MarkClientRenderableDirty( this );
+}
+
+void CDmeVMFEntity::SetRenderAngles( const QAngle &angles )
+{
+ m_vecLocalAngles.Set( Vector( angles.x, angles.y, angles.z ) ); // FIXME: angles is a vector due to the vmf "angles" having a problem parsing...
+ clienttools->MarkClientRenderableDirty( this );
+}
+
+
+//-----------------------------------------------------------------------------
+// Draws the helper for the entity
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::DrawSprite( IMaterial *pMaterial )
+{
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+
+ float t = 0.5f * sin( Plat_FloatTime() * M_PI / 1.0f ) + 0.5f;
+
+ pRenderContext->Bind( pMaterial );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh();
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 4, 4 );
+
+ unsigned char nBaseR = 255;
+ unsigned char nBaseG = 255;
+ unsigned char nBaseB = 255;
+ unsigned char nAlpha = m_bIsDirty ? (unsigned char)(255 * t) : 255;
+
+ meshBuilder.Position3f( -SPHERE_RADIUS, -SPHERE_RADIUS, 0.0f );
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
+ meshBuilder.BoneWeight( 0, 1.0f );
+ meshBuilder.BoneMatrix( 0, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( SPHERE_RADIUS, -SPHERE_RADIUS, 0.0f );
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
+ meshBuilder.BoneWeight( 0, 1.0f );
+ meshBuilder.BoneMatrix( 0, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( SPHERE_RADIUS, SPHERE_RADIUS, 0.0f );
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
+ meshBuilder.BoneWeight( 0, 1.0f );
+ meshBuilder.BoneMatrix( 0, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( -SPHERE_RADIUS, SPHERE_RADIUS, 0.0f );
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
+ meshBuilder.BoneWeight( 0, 1.0f );
+ meshBuilder.BoneMatrix( 0, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.FastIndex( 0 );
+ meshBuilder.FastIndex( 1 );
+ meshBuilder.FastIndex( 3 );
+ meshBuilder.FastIndex( 2 );
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Draws the helper for the entity
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::DrawDragHelpers( IMaterial *pMaterial )
+{
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+
+ float t = 0.5f * sin( Plat_FloatTime() * M_PI / 1.0f ) + 0.5f;
+
+ VMatrix worldToCamera;
+ // pRenderContext->GetMatrix( MATERIAL_VIEW, &worldToCamera );
+ worldToCamera.Identity();
+ worldToCamera.SetTranslation( m_vecLocalOrigin );
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadMatrix( worldToCamera );
+
+ pRenderContext->FogMode( MATERIAL_FOG_NONE );
+ pRenderContext->SetNumBoneWeights( 0 );
+ pRenderContext->CullMode( MATERIAL_CULLMODE_CW );
+
+ pRenderContext->Bind( pMaterial );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh();
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_LINES, 3 );
+
+ unsigned char nBaseR = 255;
+ unsigned char nBaseG = 255;
+ unsigned char nBaseB = 255;
+ unsigned char nAlpha = m_bIsDirty ? (unsigned char)(255 * t) : 255;
+
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( 0, 0, 0 );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( SPHERE_RADIUS * 10, 0, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( 0, 0, 0 );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( 0, SPHERE_RADIUS * 10, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( 0, 0, 0 );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( 0, 0, SPHERE_RADIUS * 10 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+
+ pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PopMatrix();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Draws the helper for the entity
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::DrawFloorTarget( IMaterial *pMaterial )
+{
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+
+ float t = 0.5f * sin( Plat_FloatTime() * M_PI / 1.0f ) + 0.5f;
+
+ // test movement
+ Ray_t ray;
+ CTraceFilterWorldAndPropsOnly traceFilter;
+ CBaseTrace tr;
+ ray.Init( m_vecLocalOrigin.Get()+ Vector( 0, 0, 10 ), m_vecLocalOrigin.Get() + Vector( 0,0, -128 ), Vector( -13, -13, 0 ), Vector( 13, 13, 10 ) );
+ enginetools->TraceRayServer( ray, MASK_OPAQUE, &traceFilter, &tr );
+
+
+ VMatrix worldToCamera;
+ // pRenderContext->GetMatrix( MATERIAL_VIEW, &worldToCamera );
+ worldToCamera.Identity();
+ worldToCamera.SetTranslation( tr.endpos );
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadMatrix( worldToCamera );
+
+ pRenderContext->FogMode( MATERIAL_FOG_NONE );
+ pRenderContext->SetNumBoneWeights( 0 );
+ pRenderContext->CullMode( MATERIAL_CULLMODE_CW );
+
+ pRenderContext->Bind( pMaterial );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh();
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_LINES, 3 );
+
+ unsigned char nBaseR = 255;
+ unsigned char nBaseG = 255;
+ unsigned char nBaseB = 0;
+ unsigned char nAlpha = m_bIsDirty ? (unsigned char)(255 * t) : 255;
+
+ float block[4][2][3] = {
+ { { -13, -13, 0 }, { -13, -13, 10 } },
+ { { 13, -13, 0 }, { 13, -13, 10 } },
+ { { 13, 13, 0 }, { 13, 13, 10 } },
+ { { -13, 13, 0 }, { -13, 13, 10 } } };
+
+ for (int i = 0; i < 4; i++)
+ {
+ int j = (i + 1) % 4;
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( block[i][0][0], block[i][0][1], block[i][0][2] );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( block[i][1][0], block[i][1][1], block[i][1][2] );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( block[i][0][0], block[i][0][1], block[i][0][2] );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( block[j][0][0], block[j][0][1], block[j][0][2] );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( block[i][1][0], block[i][1][1], block[i][1][2] );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( block[j][1][0], block[j][1][1], block[j][1][2] );
+ meshBuilder.AdvanceVertex();
+ }
+
+ // positive X
+ meshBuilder.Color4ub( 255, 0, 0, nAlpha );
+ meshBuilder.Position3f( 0, 0, 10 );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( 255, 0, 0, nAlpha );
+ meshBuilder.Position3f( 10, 0, 10 );
+ meshBuilder.AdvanceVertex();
+
+ // positive Y
+ meshBuilder.Color4ub( 0, 255, 0, nAlpha );
+ meshBuilder.Position3f( 0, 0, 10 );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( 0, 255, 0, nAlpha );
+ meshBuilder.Position3f( 0, 10, 10 );
+ meshBuilder.AdvanceVertex();
+
+ // just Z
+ meshBuilder.Color4ub( 255, 255, 255, nAlpha );
+ meshBuilder.Position3f( 0, 0, 10 );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( 255, 255, 255, nAlpha );
+ meshBuilder.Position3f( 0, 0, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+
+ pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PopMatrix();
+}
+
+
+//-----------------------------------------------------------------------------
+// Draws the helper for the entity
+//-----------------------------------------------------------------------------
+int CDmeVMFEntity::DrawModel( int flags )
+{
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+
+ bool bSelected = ( g_pVcdBlockTool->GetCurrentEntity().Get() == this );
+ if ( !m_bInfoTarget )
+ {
+ // If we have a visible engine entity, we don't need to draw it here
+ // info targets always draw though, because they have no visible model.
+ CDisableUndoScopeGuard guard;
+ float t = 0.5f * sin( Plat_FloatTime() * M_PI / 1.0f ) + 0.5f;
+ unsigned char nAlpha = m_bIsDirty ? (unsigned char)(255 * t) : 255;
+ if ( bSelected )
+ {
+ GetMDL()->m_Color.SetColor( 255, 64, 64, nAlpha );
+ }
+ else
+ {
+ GetMDL()->m_Color.SetColor( 255, 255, 255, nAlpha );
+ }
+ return BaseClass::DrawModel( flags );
+ }
+
+ Assert( IsDrawingInEngine() );
+
+ matrix3x4_t mat;
+ VMatrix worldToCamera, cameraToWorld;
+ pRenderContext->GetMatrix( MATERIAL_VIEW, &worldToCamera );
+ MatrixInverseTR( worldToCamera, cameraToWorld );
+ MatrixCopy( cameraToWorld.As3x4(), mat );
+ MatrixSetColumn( m_vecLocalOrigin, 3, mat );
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadMatrix( mat );
+
+ pRenderContext->FogMode( MATERIAL_FOG_NONE );
+ pRenderContext->SetNumBoneWeights( 0 );
+ pRenderContext->CullMode( MATERIAL_CULLMODE_CW );
+
+ DrawSprite( m_InfoTargetSprite );
+ if ( bSelected )
+ {
+ DrawSprite( m_SelectedInfoTarget );
+
+ DrawFloorTarget( m_Wireframe );
+
+ if (g_pVcdBlockTool->IsInNodeDrag())
+ {
+ DrawDragHelpers( m_Wireframe );
+ }
+ // DrawLine( Vector( 0, 0, 0 ), Vector( 10, 0, 0 ), 0, 255, 255, 255 );
+ }
+
+ pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PopMatrix();
+
+ return 1;
+}
+
+
+bool CDmeVMFEntity::CopyFromServer( CBaseEntity *pServerEnt )
+{
+ CopyFromServer( pServerEnt, "targetname" );
+ CopyFromServer( pServerEnt, "classname" );
+ CopyFromServer( pServerEnt, "origin" );
+ CopyFromServer( pServerEnt, "angles" );
+
+ return true;
+}
+
+bool CDmeVMFEntity::CopyFromServer( CBaseEntity *pServerEnt, const char *szField )
+{
+ return CopyFromServer( pServerEnt, szField, szField );
+}
+
+bool CDmeVMFEntity::CopyFromServer( CBaseEntity *pServerEnt, const char *szSrcField, const char *szDstField )
+{
+ char text[256];
+ if ( servertools->GetKeyValue( pServerEnt, szSrcField, text, sizeof( text ) ) )
+ {
+ SetValueFromString( szDstField, text );
+ return true;
+ }
+ return false;
+}
+
+bool CDmeVMFEntity::CopyToServer( void )
+{
+ if (GetEntityId() != 0)
+ {
+ CBaseEntity *pServerEntity = servertools->FindEntityByHammerID( GetEntityId() );
+ if (pServerEntity != NULL)
+ {
+ servertools->SetKeyValue( pServerEntity, "origin", m_vecLocalOrigin.Get() );
+ // FIXME: isn't there a string to vector conversion?
+ Vector tmp( m_vecLocalAngles.Get().x, m_vecLocalAngles.Get().y, m_vecLocalAngles.Get().z );
+ servertools->SetKeyValue( pServerEntity, "angles", tmp );
+ return true;
+ }
+ else
+ {
+ // FIXME: does one need to be spawned?
+ }
+ }
+ return false;
+}
+
+bool CDmeVMFEntity::IsSameOnServer( CBaseEntity *pServerEntity )
+{
+ char text[256];
+
+ if (!pServerEntity)
+ {
+ return false;
+ }
+
+ // FIXME: check targetname? Can it be edited?
+ Vector mapOrigin;
+ servertools->GetKeyValue( pServerEntity, "origin", text, sizeof( text ) );
+ sscanf( text, "%f %f %f", &mapOrigin.x, &mapOrigin.y, &mapOrigin.z );
+ Vector mapAngles;
+ servertools->GetKeyValue( pServerEntity, "angles", text, sizeof( text ) );
+ sscanf( text, "%f %f %f", &mapAngles.x, &mapAngles.y, &mapAngles.z );
+
+ return ( mapOrigin == m_vecLocalOrigin.Get() && mapAngles == m_vecLocalAngles.Get() );
+}
+
+bool CDmeVMFEntity::CreateOnServer( void )
+{
+ CBaseEntity *pServerEntity = servertools->CreateEntityByName( m_ClassName.Get() );
+
+ if (pServerEntity)
+ {
+ // test movement
+ Ray_t ray;
+ CTraceFilterWorldAndPropsOnly traceFilter;
+ CBaseTrace tr;
+ ray.Init( m_vecLocalOrigin.Get()+ Vector( 0, 0, 10 ), m_vecLocalOrigin.Get() + Vector( 0,0, -1000 ) );
+ enginetools->TraceRayServer( ray, MASK_OPAQUE, &traceFilter, &tr );
+ m_vecLocalOrigin.Set( tr.endpos );
+
+ servertools->SetKeyValue( pServerEntity, "hammerid", GetEntityId() );
+ servertools->SetKeyValue( pServerEntity, "targetname", m_TargetName.Get() );
+ servertools->SetKeyValue( pServerEntity, "origin", m_vecLocalOrigin.Get() );
+ servertools->SetKeyValue( pServerEntity, "angles", m_vecLocalAngles.Get() );
+ servertools->DispatchSpawn( pServerEntity );
+
+ return true;
+ }
+ return false;
+}
diff --git a/tools/vcdblock/dmevmfentity.h b/tools/vcdblock/dmevmfentity.h
new file mode 100644
index 0000000..5400610
--- /dev/null
+++ b/tools/vcdblock/dmevmfentity.h
@@ -0,0 +1,131 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Represents an entity in a VMF
+//
+//=============================================================================
+
+#ifndef DMEVMFENTITY_H
+#define DMEVMFENTITY_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "toolutils/dmemdlrenderable.h"
+#include "datamodel/dmelement.h"
+#include "toolframework/itoolentity.h"
+#include "materialsystem/MaterialSystemUtil.h"
+
+
+//-----------------------------------------------------------------------------
+// Represents an editable entity; draws its helpers
+//-----------------------------------------------------------------------------
+class CDmeVMFEntity : public CDmeMdlRenderable<CDmElement>
+{
+ DEFINE_ELEMENT( CDmeVMFEntity, CDmeMdlRenderable<CDmElement> );
+
+public:
+ // Inherited from CDmElement
+ virtual void OnAttributeChanged( CDmAttribute *pAttribute );
+
+public:
+ // Inherited from DmeRenderable
+ virtual const Vector &GetRenderOrigin( void );
+ virtual const QAngle &GetRenderAngles( void );
+ virtual int DrawModel( int flags );
+ virtual bool IsTransparent( void );
+ virtual void GetRenderBounds( Vector& mins, Vector& maxs );
+
+public:
+ int GetEntityId() const;
+
+ // Returns the next available entity id
+ static int GetNextEntityId();
+ static void SetNextEntityId( int nEntityId );
+
+ const char *GetClassName() const;
+ const char *GetTargetName() const;
+
+ bool IsPlaceholder() const;
+
+ // Entity Key iteration
+ CDmAttribute *FirstEntityKey();
+ CDmAttribute *NextEntityKey( CDmAttribute *pEntityKey );
+
+ // Attach/detach from an engine entity with the same editor index
+ void AttachToEngineEntity( HTOOLHANDLE hToolHandle );
+
+ void SetRenderOrigin( const Vector &vecOrigin );
+ void SetRenderAngles( const QAngle &angles );
+
+ void MarkDirty( bool bDirty = true );
+ bool IsDirty( void ) { return m_bIsDirty; };
+
+ void MarkDeleted( bool bDeleted = true );
+ bool IsDeleted( void ) { return m_bIsDeleted; };
+
+ bool CopyFromServer( CBaseEntity *pServerEnt );
+ bool CopyFromServer( CBaseEntity *pServerEnt, const char *szField );
+ bool CopyFromServer( CBaseEntity *pServerEnt, const char *szSrcField, const char *szDstField );
+ bool CopyToServer( void );
+
+ bool IsSameOnServer( CBaseEntity *pServerEntity );
+ bool CreateOnServer( void );
+
+private:
+ bool IsEntityKey( CDmAttribute *pEntityKey );
+
+ // Draws the helper for the entity
+ void DrawSprite( IMaterial *pMaterial );
+ void DrawDragHelpers( IMaterial *pMaterial );
+ void DrawFloorTarget( IMaterial *pMaterial );
+
+ CDmaVar<Vector> m_vecLocalOrigin;
+ // CDmAttributeVar<QAngle> m_vecLocalAngles;
+ CDmaVar<Vector> m_vecLocalAngles; // something funky with the vmf importer, it asserts when it's a QAngle
+
+ CDmaString m_ClassName;
+ CDmaString m_TargetName;
+ CDmaVar<bool> m_bIsPlaceholder;
+
+ // The entity it's connected to in the engine
+ HTOOLHANDLE m_hEngineEntity;
+
+ CMaterialReference m_Wireframe;
+
+ CMaterialReference m_SelectedInfoTarget;
+ CMaterialReference m_InfoTargetSprite;
+
+ // pretty sure this entity is edited
+ bool m_bIsDirty;
+
+ // entity needs to be deleted
+ CDmaVar<bool> m_bIsDeleted;
+
+ // FIXME: This is a hack for info targets
+ bool m_bInfoTarget;
+
+ // Used to store the next unique entity id;
+ static int s_nNextEntityId;
+};
+
+
+//-----------------------------------------------------------------------------
+// Inline methods
+//-----------------------------------------------------------------------------
+inline const char *CDmeVMFEntity::GetClassName() const
+{
+ return m_ClassName;
+}
+
+inline const char *CDmeVMFEntity::GetTargetName() const
+{
+ return m_TargetName;
+}
+
+inline bool CDmeVMFEntity::IsPlaceholder() const
+{
+ return m_bIsPlaceholder;
+}
+
+
+#endif // DMEVMFENTITY_H
diff --git a/tools/vcdblock/infotargetbrowserpanel.cpp b/tools/vcdblock/infotargetbrowserpanel.cpp
new file mode 100644
index 0000000..50e5729
--- /dev/null
+++ b/tools/vcdblock/infotargetbrowserpanel.cpp
@@ -0,0 +1,297 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Singleton dialog that generates and presents the entity report.
+//
+//===========================================================================//
+
+#include "InfoTargetBrowserPanel.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "iregistry.h"
+#include "vgui/ivgui.h"
+#include "vgui_controls/listpanel.h"
+#include "vgui_controls/textentry.h"
+#include "vgui_controls/checkbutton.h"
+#include "vgui_controls/combobox.h"
+#include "vgui_controls/radiobutton.h"
+#include "vgui_controls/messagebox.h"
+#include "vcdblockdoc.h"
+#include "vcdblocktool.h"
+#include "datamodel/dmelement.h"
+#include "vgui/keycode.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Sort by target name
+//-----------------------------------------------------------------------------
+static int __cdecl TargetNameSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ const char *string1 = item1.kv->GetString("targetname");
+ const char *string2 = item2.kv->GetString("targetname");
+ int nRetVal = Q_stricmp( string1, string2 );
+ if ( nRetVal != 0 )
+ return nRetVal;
+
+ string1 = item1.kv->GetString("classname");
+ string2 = item2.kv->GetString("classname");
+ return Q_stricmp( string1, string2 );
+}
+
+//-----------------------------------------------------------------------------
+// Sort by class name
+//-----------------------------------------------------------------------------
+static int __cdecl ClassNameSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ const char *string1 = item1.kv->GetString("classname");
+ const char *string2 = item2.kv->GetString("classname");
+ int nRetVal = Q_stricmp( string1, string2 );
+ if ( nRetVal != 0 )
+ return nRetVal;
+
+ string1 = item1.kv->GetString("targetname");
+ string2 = item2.kv->GetString("targetname");
+ return Q_stricmp( string1, string2 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CInfoTargetBrowserPanel::CInfoTargetBrowserPanel( CVcdBlockDoc *pDoc, vgui::Panel* pParent, const char *pName )
+ : BaseClass( pParent, pName ), m_pDoc( pDoc )
+{
+ SetPaintBackgroundEnabled( true );
+
+ m_pEntities = new vgui::ListPanel( this, "Entities" );
+ m_pEntities->AddColumnHeader( 0, "targetname", "Name", 52, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pEntities->AddColumnHeader( 1, "classname", "Class Name", 52, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pEntities->SetColumnSortable( 0, true );
+ m_pEntities->SetColumnSortable( 1, true );
+ m_pEntities->SetEmptyListText( "No info_targets" );
+ // m_pEntities->SetDragEnabled( true );
+ m_pEntities->AddActionSignalTarget( this );
+ m_pEntities->SetSortFunc( 0, TargetNameSortFunc );
+ m_pEntities->SetSortFunc( 1, ClassNameSortFunc );
+ m_pEntities->SetSortColumn( 0 );
+
+ LoadControlSettingsAndUserConfig( "resource/infotargetbrowserpanel.res" );
+
+ UpdateEntityList();
+}
+
+CInfoTargetBrowserPanel::~CInfoTargetBrowserPanel()
+{
+ SaveUserConfig();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Shows the most recent selected object in properties window
+//-----------------------------------------------------------------------------
+void CInfoTargetBrowserPanel::OnProperties(void)
+{
+ int iSel = m_pEntities->GetSelectedItem( 0 );
+ KeyValues *kv = m_pEntities->GetItem( iSel );
+ CDmeVMFEntity *pEntity = CastElement< CDmeVMFEntity >( (CDmElement *)kv->GetPtr( "entity" ) );
+ g_pVcdBlockTool->ShowEntityInEntityProperties( pEntity );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Deletes the marked objects.
+//-----------------------------------------------------------------------------
+void CInfoTargetBrowserPanel::OnDeleteEntities(void)
+{
+ int iSel = m_pEntities->GetSelectedItem( 0 );
+
+ {
+ // This is undoable
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Delete Entities", "Delete Entities" );
+
+ //
+ // Build a list of objects to delete.
+ //
+ int nCount = m_pEntities->GetSelectedItemsCount();
+ for (int i = 0; i < nCount; i++)
+ {
+ int nItemID = m_pEntities->GetSelectedItem(i);
+ KeyValues *kv = m_pEntities->GetItem( nItemID );
+ CDmeVMFEntity *pEntity = (CDmeVMFEntity *)kv->GetPtr( "entity" );
+ if ( pEntity )
+ {
+ m_pDoc->DeleteInfoTarget( pEntity );
+ }
+ }
+ }
+
+ // Update the list box selection.
+ if (iSel >= m_pEntities->GetItemCount())
+ {
+ iSel = m_pEntities->GetItemCount() - 1;
+ }
+ m_pEntities->SetSingleSelectedItem( iSel );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CInfoTargetBrowserPanel::OnKeyCodeTyped( vgui::KeyCode code )
+{
+ if ( code == KEY_DELETE )
+ {
+ OnDeleteEntities();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped( code );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CInfoTargetBrowserPanel::OnItemSelected( void )
+{
+ OnProperties();
+}
+
+
+//-----------------------------------------------------------------------------
+// Select a particular node
+//-----------------------------------------------------------------------------
+void CInfoTargetBrowserPanel::SelectNode( CDmeVMFEntity *pNode )
+{
+ m_pEntities->ClearSelectedItems();
+ for ( int nItemID = m_pEntities->FirstItem(); nItemID != m_pEntities->InvalidItemID(); nItemID = m_pEntities->NextItem( nItemID ) )
+ {
+ KeyValues *kv = m_pEntities->GetItem( nItemID );
+ CDmElement *pEntity = (CDmElement *)kv->GetPtr( "entity" );
+ if ( pEntity == pNode )
+ {
+ m_pEntities->AddSelectedItem( nItemID );
+ break;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when buttons are clicked
+//-----------------------------------------------------------------------------
+void CInfoTargetBrowserPanel::OnCommand( const char *pCommand )
+{
+ if ( !Q_stricmp( pCommand, "delete" ) )
+ {
+ // Confirm we want to do it
+ MessageBox *pConfirm = new MessageBox( "#VcdBlockDeleteObjects", "#VcdBlockDeleteObjectsMsg", g_pVcdBlockTool->GetRootPanel() );
+ pConfirm->AddActionSignalTarget( this );
+ pConfirm->SetOKButtonText( "Yes" );
+ pConfirm->SetCommand( new KeyValues( "DeleteEntities" ) );
+ pConfirm->SetCancelButtonVisible( true );
+ pConfirm->SetCancelButtonText( "No" );
+ pConfirm->DoModal();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "Save" ) )
+ {
+ g_pVcdBlockTool->Save();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "RestartMap" ) )
+ {
+ g_pVcdBlockTool->RestartMap();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "DropInfoTargets" ) )
+ {
+ g_pVcdBlockTool->EnterTargetDropMode();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "quicksave" ) )
+ {
+ g_pVcdBlockTool->QuickSave();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "quickload" ) )
+ {
+ g_pVcdBlockTool->QuickLoad();
+ return;
+ }
+
+ BaseClass::OnCommand( pCommand );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CInfoTargetBrowserPanel::UpdateEntityList(void)
+{
+ m_pEntities->RemoveAll();
+
+ const CDmrElementArray<CDmElement> entityList( m_pDoc->GetEntityList() );
+ if ( !entityList.IsValid() )
+ return;
+
+ int nCount = entityList.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmElement *pEntity = entityList[i];
+
+ const char *pClassName = pEntity->GetValueString( "classname" );
+ if ( !pClassName || !pClassName[0] )
+ {
+ pClassName = "<no class>";
+ }
+
+ KeyValues *kv = new KeyValues( "node" );
+ kv->SetString( "classname", pClassName );
+ kv->SetPtr( "entity", pEntity );
+
+ const char *pTargetname = pEntity->GetValueString( "targetname" );
+ if ( !pTargetname || !pTargetname[0] )
+ {
+ pTargetname = "<no targetname>";
+ }
+ kv->SetString( "targetname", pTargetname );
+
+ int nItemID = m_pEntities->AddItem( kv, 0, false, false );
+
+ // Hide everything that isn't an info_target
+ m_pEntities->SetItemVisible( nItemID, !Q_stricmp( pClassName, "info_target" ) );
+ }
+ m_pEntities->SortList();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CInfoTargetBrowserPanel::Refresh(void)
+{
+ for ( int nItemID = m_pEntities->FirstItem(); nItemID != m_pEntities->InvalidItemID(); nItemID = m_pEntities->NextItem( nItemID ) )
+ {
+ KeyValues *kv = m_pEntities->GetItem( nItemID );
+ CDmElement *pEntity = (CDmElement *)kv->GetPtr( "entity" );
+
+ const char *pTargetname = pEntity->GetValueString( "targetname" );
+ if ( !pTargetname || !pTargetname[0] )
+ {
+ pTargetname = "<no targetname>";
+ }
+ kv->SetString( "targetname", pTargetname );
+ }
+}
+
diff --git a/tools/vcdblock/infotargetbrowserpanel.h b/tools/vcdblock/infotargetbrowserpanel.h
new file mode 100644
index 0000000..3a8ecc4
--- /dev/null
+++ b/tools/vcdblock/infotargetbrowserpanel.h
@@ -0,0 +1,68 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#ifndef INFOTARGETBROWSERPANEL_H
+#define INFOTARGETBROWSERPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/editablepanel.h"
+#include "tier1/utlstring.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CVcdBlockDoc;
+class CDmeVMFEntity;
+namespace vgui
+{
+ class ComboBox;
+ class Button;
+ class TextEntry;
+ class ListPanel;
+ class CheckButton;
+ class RadioButton;
+}
+
+
+//-----------------------------------------------------------------------------
+// Panel that shows all entities in the level
+//-----------------------------------------------------------------------------
+class CInfoTargetBrowserPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CInfoTargetBrowserPanel, vgui::EditablePanel );
+
+public:
+ CInfoTargetBrowserPanel( CVcdBlockDoc *pDoc, vgui::Panel* pParent, const char *pName ); // standard constructor
+ virtual ~CInfoTargetBrowserPanel();
+
+ // Inherited from Panel
+ virtual void OnCommand( const char *pCommand );
+ virtual void OnKeyCodeTyped( vgui::KeyCode code );
+
+ // Methods related to updating the listpanel
+ void UpdateEntityList();
+ void Refresh();
+
+ // Select a particular node
+ void SelectNode( CDmeVMFEntity *pNode );
+
+private:
+ // Messages handled
+ MESSAGE_FUNC( OnDeleteEntities, "DeleteEntities" );
+ MESSAGE_FUNC( OnItemSelected, "ItemSelected" );
+
+ // Shows the most recent selected object in properties window
+ void OnProperties();
+
+ CVcdBlockDoc *m_pDoc;
+ vgui::ListPanel *m_pEntities;
+};
+
+
+#endif // INFOTARGETBROWSERPANEL_H
diff --git a/tools/vcdblock/infotargetpropertiespanel.cpp b/tools/vcdblock/infotargetpropertiespanel.cpp
new file mode 100644
index 0000000..1ba56f4
--- /dev/null
+++ b/tools/vcdblock/infotargetpropertiespanel.cpp
@@ -0,0 +1,225 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Singleton dialog that generates and presents the entity report.
+//
+//===========================================================================//
+
+#include "InfoTargetPropertiesPanel.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "iregistry.h"
+#include "vgui/ivgui.h"
+#include "vgui_controls/listpanel.h"
+#include "vgui_controls/textentry.h"
+#include "vgui_controls/checkbutton.h"
+#include "vgui_controls/combobox.h"
+#include "vgui_controls/radiobutton.h"
+#include "vgui_controls/messagebox.h"
+#include "vgui_controls/scrollbar.h"
+#include "vcdblockdoc.h"
+#include "vcdblocktool.h"
+#include "datamodel/dmelement.h"
+#include "dmevmfentity.h"
+#include "dme_controls/soundpicker.h"
+#include "dme_controls/soundrecordpanel.h"
+#include "matsys_controls/picker.h"
+#include "vgui_controls/fileopendialog.h"
+#include "filesystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+class CScrollableEditablePanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CScrollableEditablePanel, vgui::EditablePanel );
+
+public:
+ CScrollableEditablePanel( vgui::Panel *pParent, vgui::EditablePanel *pChild, const char *pName );
+ virtual ~CScrollableEditablePanel() {}
+ virtual void PerformLayout();
+
+ MESSAGE_FUNC( OnScrollBarSliderMoved, "ScrollBarSliderMoved" );
+
+private:
+ vgui::ScrollBar *m_pScrollBar;
+ vgui::EditablePanel *m_pChild;
+};
+
+
+CScrollableEditablePanel::CScrollableEditablePanel( vgui::Panel *pParent, vgui::EditablePanel *pChild, const char *pName ) :
+ BaseClass( pParent, pName )
+{
+ m_pChild = pChild;
+ m_pChild->SetParent( this );
+
+ m_pScrollBar = new vgui::ScrollBar( this, "VerticalScrollBar", true );
+ m_pScrollBar->SetWide( 16 );
+ m_pScrollBar->SetAutoResize( PIN_TOPRIGHT, AUTORESIZE_DOWN, 0, 0, -16, 0 );
+ m_pScrollBar->AddActionSignalTarget( this );
+}
+
+void CScrollableEditablePanel::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ m_pChild->SetWide( GetWide() - 16 );
+ m_pScrollBar->SetRange( 0, m_pChild->GetTall() );
+ m_pScrollBar->SetRangeWindow( GetTall() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when the scroll bar moves
+//-----------------------------------------------------------------------------
+void CScrollableEditablePanel::OnScrollBarSliderMoved()
+{
+ InvalidateLayout();
+
+ int nScrollAmount = m_pScrollBar->GetValue();
+ m_pChild->SetPos( 0, -nScrollAmount );
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CInfoTargetPropertiesPanel::CInfoTargetPropertiesPanel( CVcdBlockDoc *pDoc, vgui::Panel* pParent )
+ : BaseClass( pParent, "InfoTargetPropertiesPanel" ), m_pDoc( pDoc )
+{
+ SetPaintBackgroundEnabled( true );
+ SetKeyBoardInputEnabled( true );
+
+ m_pInfoTarget = new vgui::EditablePanel( (vgui::Panel*)NULL, "InfoTarget" );
+
+ m_pTargetName = new vgui::TextEntry( m_pInfoTarget, "TargetName" );
+ m_pTargetName->AddActionSignalTarget( this );
+
+ m_pTargetPosition[0] = new vgui::TextEntry( m_pInfoTarget, "PositionX" );
+ m_pTargetPosition[0]->AddActionSignalTarget( this );
+ m_pTargetPosition[1] = new vgui::TextEntry( m_pInfoTarget, "PositionY" );
+ m_pTargetPosition[1]->AddActionSignalTarget( this );
+ m_pTargetPosition[2] = new vgui::TextEntry( m_pInfoTarget, "PositionZ" );
+ m_pTargetPosition[2]->AddActionSignalTarget( this );
+
+ m_pTargetOrientation[0] = new vgui::TextEntry( m_pInfoTarget, "Pitch" );
+ m_pTargetOrientation[0]->AddActionSignalTarget( this );
+ m_pTargetOrientation[1] = new vgui::TextEntry( m_pInfoTarget, "Yaw" );
+ m_pTargetOrientation[1]->AddActionSignalTarget( this );
+ m_pTargetOrientation[2] = new vgui::TextEntry( m_pInfoTarget, "Roll" );
+ m_pTargetOrientation[2]->AddActionSignalTarget( this );
+
+ m_pInfoTarget->LoadControlSettings( "resource/infotargetpropertiessubpanel_target.res" );
+
+ m_pInfoTargetScroll = new CScrollableEditablePanel( this, m_pInfoTarget, "InfoTargetScroll" );
+
+ LoadControlSettings( "resource/infotargetpropertiespanel.res" );
+
+ m_pInfoTargetScroll->SetVisible( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Text to attribute...
+//-----------------------------------------------------------------------------
+void CInfoTargetPropertiesPanel::TextEntryToAttribute( vgui::TextEntry *pEntry, const char *pAttributeName )
+{
+ int nLen = pEntry->GetTextLength();
+ char *pBuf = (char*)_alloca( nLen+1 );
+ pEntry->GetText( pBuf, nLen+1 );
+ m_hEntity->SetValue( pAttributeName, pBuf );
+}
+
+void CInfoTargetPropertiesPanel::TextEntriesToVector( vgui::TextEntry *pEntry[3], const char *pAttributeName )
+{
+ Vector vec;
+ for ( int i = 0; i < 3; ++i )
+ {
+ int nLen = pEntry[i]->GetTextLength();
+ char *pBuf = (char*)_alloca( nLen+1 );
+ pEntry[i]->GetText( pBuf, nLen+1 );
+ vec[i] = atof( pBuf );
+ }
+ m_hEntity->SetValue( pAttributeName, vec );
+ clienttools->MarkClientRenderableDirty( m_hEntity );
+}
+
+
+//-----------------------------------------------------------------------------
+// Updates entity state when text fields change
+//-----------------------------------------------------------------------------
+void CInfoTargetPropertiesPanel::UpdateInfoTarget()
+{
+ if ( !m_hEntity.Get() )
+ return;
+
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Info Target Change", "Info Target Change" );
+ TextEntryToAttribute( m_pTargetName, "targetname" );
+ TextEntriesToVector( m_pTargetPosition, "origin" );
+ TextEntriesToVector( m_pTargetOrientation, "angles" );
+ m_hEntity->MarkDirty();
+}
+
+
+//-----------------------------------------------------------------------------
+// Populates the info_target fields
+//-----------------------------------------------------------------------------
+void CInfoTargetPropertiesPanel::PopulateInfoTargetFields()
+{
+ if ( !m_hEntity.Get() )
+ return;
+
+ m_pTargetName->SetText( m_hEntity->GetTargetName() );
+
+ Vector vecPosition = m_hEntity->GetRenderOrigin();
+ QAngle vecAngles = m_hEntity->GetRenderAngles();
+
+ for ( int i = 0; i < 3; ++i )
+ {
+ char pTemp[512];
+ Q_snprintf( pTemp, sizeof(pTemp), "%.2f", vecPosition[i] );
+ m_pTargetPosition[i]->SetText( pTemp );
+
+ Q_snprintf( pTemp, sizeof(pTemp), "%.2f", vecAngles[i] );
+ m_pTargetOrientation[i]->SetText( pTemp );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the object to look at
+//-----------------------------------------------------------------------------
+void CInfoTargetPropertiesPanel::SetObject( CDmeVMFEntity *pEntity )
+{
+ m_hEntity = pEntity;
+ m_pInfoTargetScroll->SetVisible( false );
+
+ if ( pEntity )
+ {
+ if ( !Q_stricmp( pEntity->GetClassName(), "info_target" ) )
+ {
+ PopulateInfoTargetFields();
+ m_pInfoTargetScroll->SetVisible( true );
+ m_pTargetName->RequestFocus();
+ return;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when text is changed
+//-----------------------------------------------------------------------------
+void CInfoTargetPropertiesPanel::OnTextChanged( KeyValues *pParams )
+{
+ vgui::Panel *pPanel = (vgui::Panel*)pParams->GetPtr( "panel" );
+ if ( pPanel->GetParent() == m_pInfoTarget )
+ {
+ UpdateInfoTarget();
+ return;
+ }
+}
+
+
+
diff --git a/tools/vcdblock/infotargetpropertiespanel.h b/tools/vcdblock/infotargetpropertiespanel.h
new file mode 100644
index 0000000..b43b62b
--- /dev/null
+++ b/tools/vcdblock/infotargetpropertiespanel.h
@@ -0,0 +1,76 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#ifndef INFOTARGETPROPERTIESPANEL_H
+#define INFOTARGETPROPERTIESPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/editablepanel.h"
+#include "tier1/utlstring.h"
+#include "datamodel/dmehandle.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CVcdBlockDoc;
+class CDmeVMFEntity;
+class CScrollableEditablePanel;
+
+namespace vgui
+{
+ class ComboBox;
+ class Button;
+ class TextEntry;
+ class ListPanel;
+ class CheckButton;
+ class RadioButton;
+}
+
+
+//-----------------------------------------------------------------------------
+// Panel that shows all entities in the level
+//-----------------------------------------------------------------------------
+class CInfoTargetPropertiesPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CInfoTargetPropertiesPanel, vgui::EditablePanel );
+
+public:
+ CInfoTargetPropertiesPanel( CVcdBlockDoc *pDoc, vgui::Panel* pParent ); // standard constructor
+
+ // Sets the object to look at
+ void SetObject( CDmeVMFEntity *pEntity );
+
+private:
+ // Populates the info_target fields
+ void PopulateInfoTargetFields();
+
+ // Text to attribute...
+ void TextEntryToAttribute( vgui::TextEntry *pEntry, const char *pAttributeName );
+ void TextEntriesToVector( vgui::TextEntry *pEntry[3], const char *pAttributeName );
+
+ // Updates entity state when text fields change
+ void UpdateInfoTarget();
+
+ // Messages handled
+ MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", kv );
+
+ CVcdBlockDoc *m_pDoc;
+
+ vgui::EditablePanel *m_pInfoTargetScroll;
+ vgui::EditablePanel *m_pInfoTarget;
+
+ vgui::TextEntry *m_pTargetName;
+ vgui::TextEntry *m_pTargetPosition[3];
+ vgui::TextEntry *m_pTargetOrientation[3];
+
+ CDmeHandle< CDmeVMFEntity > m_hEntity;
+};
+
+
+#endif // INFOTARGETPROPERTIESPANEL_H
diff --git a/tools/vcdblock/vcdblock.vpc b/tools/vcdblock/vcdblock.vpc
new file mode 100644
index 0000000..187efc7
--- /dev/null
+++ b/tools/vcdblock/vcdblock.vpc
@@ -0,0 +1,64 @@
+//-----------------------------------------------------------------------------
+// VCDBLOCK.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin\tools"
+
+$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE,.\,..\common;$SRCDIR\game\shared"
+ $PreprocessorDefinitions "$BASE;VCDBLOCK_EXPORTS"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "$BASE Psapi.lib"
+ }
+}
+
+$Project "Vcdblock"
+{
+ $Folder "Source Files"
+ {
+ $File "dmevmfentity.cpp"
+ $File "infotargetbrowserpanel.cpp"
+ $File "infotargetpropertiespanel.cpp"
+ $File "$SRCDIR\public\interpolatortypes.cpp"
+ $File "$SRCDIR\public\registry.cpp"
+ $File "vcdblockdoc.cpp"
+ $File "vcdblocktool.cpp"
+ $File "$SRCDIR\public\vgui_controls\vgui_controls.cpp"
+ }
+
+ $Folder "Header Files"
+ {
+ $File "dmevmfentity.h"
+ $File "infotargetbrowserpanel.h"
+ $File "infotargetpropertiespanel.h"
+ $File "$SRCDIR\public\mathlib\mathlib.h"
+ $File "vcdblockdoc.h"
+ $File "vcdblocktool.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib datamodel
+ $Lib dme_controls
+ $Lib dmserializers
+ $Lib mathlib
+ $Lib matsys_controls
+ $Lib movieobjects
+ $Lib sfmobjects
+ $Lib tier2
+ $Lib tier3
+ $Lib toolutils
+ $Lib vgui_controls
+ }
+}
diff --git a/tools/vcdblock/vcdblockdoc.cpp b/tools/vcdblock/vcdblockdoc.cpp
new file mode 100644
index 0000000..313e83f
--- /dev/null
+++ b/tools/vcdblock/vcdblockdoc.cpp
@@ -0,0 +1,630 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "vcdblockdoc.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "toolutils/enginetools_int.h"
+#include "filesystem.h"
+#include "vcdblocktool.h"
+#include "toolframework/ienginetool.h"
+#include "dmevmfentity.h"
+#include "datamodel/idatamodel.h"
+#include "toolutils/attributeelementchoicelist.h"
+#include "infotargetbrowserpanel.h"
+#include "vgui_controls/messagebox.h"
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CVcdBlockDoc::CVcdBlockDoc( IVcdBlockDocCallback *pCallback ) : m_pCallback( pCallback )
+{
+ m_hVMFRoot = NULL;
+ m_hEditRoot = NULL;
+ m_pBSPFileName[0] = 0;
+ m_pVMFFileName[0] = 0;
+ m_pEditFileName[0] = 0;
+ m_bDirty = false;
+ g_pDataModel->InstallNotificationCallback( this );
+}
+
+CVcdBlockDoc::~CVcdBlockDoc()
+{
+ g_pDataModel->RemoveNotificationCallback( this );
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from INotifyUI
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ OnDataChanged( pReason, nNotifySource, nNotifyFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the file name
+//-----------------------------------------------------------------------------
+const char *CVcdBlockDoc::GetBSPFileName()
+{
+ return m_pBSPFileName;
+}
+
+const char *CVcdBlockDoc::GetVMFFileName()
+{
+ return m_pVMFFileName;
+}
+
+void CVcdBlockDoc::SetVMFFileName( const char *pFileName )
+{
+ Q_strncpy( m_pVMFFileName, pFileName, sizeof( m_pVMFFileName ) );
+ Q_FixSlashes( m_pVMFFileName );
+ SetDirty( true );
+}
+
+const char *CVcdBlockDoc::GetEditFileName()
+{
+ return m_pEditFileName;
+}
+
+void CVcdBlockDoc::SetEditFileName( const char *pFileName )
+{
+ Q_strncpy( m_pEditFileName, pFileName, sizeof( m_pEditFileName ) );
+ Q_FixSlashes( m_pEditFileName );
+ SetDirty( true );
+}
+
+//-----------------------------------------------------------------------------
+// Dirty bits
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::SetDirty( bool bDirty )
+{
+ m_bDirty = bDirty;
+}
+
+bool CVcdBlockDoc::IsDirty() const
+{
+ return m_bDirty;
+}
+
+
+//-----------------------------------------------------------------------------
+// Saves/loads from file
+//-----------------------------------------------------------------------------
+bool CVcdBlockDoc::LoadFromFile( const char *pFileName )
+{
+ Assert( !m_hVMFRoot.Get() );
+ Assert( !m_hEditRoot.Get() );
+
+ CAppDisableUndoScopeGuard guard( "CVcdBlockDoc::LoadFromFile", NOTIFY_CHANGE_OTHER );
+ SetDirty( false );
+
+ if ( !pFileName[0] )
+ return false;
+
+ // Construct VMF file name from the BSP
+ const char *pGame = Q_stristr( pFileName, "\\game\\" );
+ if ( !pGame )
+ {
+ pGame = Q_stristr( pFileName, "\\content\\" );
+ if ( !pGame )
+ return false;
+ }
+
+ // Compute the map name
+ const char *pMaps = Q_stristr( pFileName, "\\maps\\" );
+ if ( !pMaps )
+ return false;
+
+ // Build map name
+ char mapname[ 256 ];
+ Q_StripExtension( pFileName, mapname, sizeof(mapname) );
+ char *pszFileName = (char*)Q_UnqualifiedFileName(mapname);
+
+ int nLen = (int)( (size_t)pGame - (size_t)pFileName ) + 1;
+ Q_strncpy( m_pVMFFileName, pFileName, nLen );
+ Q_strncat( m_pVMFFileName, "\\content\\", sizeof(m_pVMFFileName) );
+ Q_strncat( m_pVMFFileName, pGame + 6, sizeof(m_pVMFFileName) );
+ Q_SetExtension( m_pVMFFileName, ".vmf", sizeof(m_pVMFFileName) );
+
+ // Make sure new entities start with ids at 0
+ CDmeVMFEntity::SetNextEntityId( 0 );
+
+ // Build the Edit file name
+ Q_StripExtension( m_pVMFFileName, m_pEditFileName, sizeof(m_pEditFileName) );
+ Q_strncat( m_pEditFileName, ".vle", sizeof( m_pEditFileName ) );
+
+ // Store the BSP file name
+ Q_strncpy( m_pBSPFileName, pFileName, sizeof( m_pBSPFileName ) );
+
+ // Set the txt file name.
+ // If we loaded a .bsp, clear out what we're doing
+ // load the Edits file into memory, assign it as our "root"
+ CDmElement *pEdit = NULL;
+ if ( !V_stricmp( Q_GetFileExtension( pFileName ), "vle" ) )
+ {
+ if ( g_pDataModel->RestoreFromFile( m_pEditFileName, NULL, "vmf", &pEdit ) != DMFILEID_INVALID )
+ {
+ // If we successfully read the file in, ask it for the max hammer id
+ //int nMaxHammerId = pVMF->GetAttributeValue<int>( "maxHammerId" );
+ //CDmeVMFEntity::SetNextEntityId( nMaxHammerId + 1 );
+ m_hEditRoot = pEdit;
+ SetDirty( false );
+ }
+ }
+
+ if (pEdit == NULL)
+ {
+ if ( g_pFileSystem->FileExists( m_pEditFileName ) )
+ {
+ char pBuf[1024];
+ Q_snprintf( pBuf, sizeof(pBuf), "File %s already exists!\n", m_pEditFileName );
+ m_pEditFileName[0] = 0;
+ vgui::MessageBox *pMessageBox = new vgui::MessageBox( "Unable to overwrite file!\n", pBuf, g_pVcdBlockTool );
+ pMessageBox->DoModal( );
+ return false;
+ }
+
+ DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( m_pEditFileName );
+ m_hEditRoot = CreateElement<CDmElement>( "root", fileid );
+ m_hEditRoot->AddAttribute( "entities", AT_ELEMENT_ARRAY );
+ g_pDataModel->SetFileRoot( fileid, m_hEditRoot );
+ SetDirty( true );
+ }
+
+ guard.Release();
+
+ // tell the engine to actually load the map
+ char cmd[ 256 ];
+ Q_snprintf( cmd, sizeof( cmd ), "disconnect; map %s\n", pszFileName );
+ enginetools->Command( cmd );
+ enginetools->Execute( );
+
+ return true;
+}
+
+
+void CVcdBlockDoc::SaveToFile( )
+{
+ if ( m_hEditRoot.Get() && m_pEditFileName && m_pEditFileName[0] )
+ {
+ g_pDataModel->SaveToFile( m_pEditFileName, NULL, "keyvalues", "vmf", m_hEditRoot );
+ }
+
+ SetDirty( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the root object
+//-----------------------------------------------------------------------------
+CDmElement *CVcdBlockDoc::GetRootObject()
+{
+ return m_hEditRoot;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the entity list
+//-----------------------------------------------------------------------------
+CDmAttribute *CVcdBlockDoc::GetEntityList()
+{
+ return m_hEditRoot ? m_hEditRoot->GetAttribute( "entities", AT_ELEMENT_ARRAY ) : NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::AddNewInfoTarget( const Vector &vecOrigin, const QAngle &angAngles )
+{
+ CDmrElementArray<> entities = GetEntityList();
+
+ CDmeVMFEntity *pTarget;
+ {
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Add Info Target", "Add Info Target" );
+
+ pTarget = CreateElement<CDmeVMFEntity>( "", entities.GetOwner()->GetFileId() );
+ pTarget->SetValue( "classname", "info_target" );
+ pTarget->SetRenderOrigin( vecOrigin );
+ pTarget->SetRenderAngles( angAngles );
+
+ entities.AddToTail( pTarget );
+ pTarget->MarkDirty();
+ pTarget->DrawInEngine( true );
+ }
+
+ g_pVcdBlockTool->GetInfoTargetBrowser()->SelectNode( pTarget );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::AddNewInfoTarget( void )
+{
+ Vector vecOrigin;
+ QAngle angAngles;
+ float flFov;
+ clienttools->GetLocalPlayerEyePosition( vecOrigin, angAngles, flFov );
+ AddNewInfoTarget( vecOrigin, vec3_angle );
+}
+
+
+//-----------------------------------------------------------------------------
+// Deletes a commentary node
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::DeleteInfoTarget( CDmeVMFEntity *pNode )
+{
+ CDmrElementArray<CDmElement> entities = GetEntityList();
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ if ( pNode == entities[i] )
+ {
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Delete Info Target", "Delete Info Target" );
+ CDmeVMFEntity *pNode = CastElement< CDmeVMFEntity >( entities[ i ] );
+ pNode->DrawInEngine( false );
+ entities.FastRemove( i );
+ return;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &vecOrigin -
+// &angAbsAngles -
+// Output : CDmeVMFEntity
+//-----------------------------------------------------------------------------
+CDmeVMFEntity *CVcdBlockDoc::GetInfoTargetForLocation( Vector &vecOrigin, QAngle &angAbsAngles )
+{
+ const CDmrElementArray<> entities = GetEntityList();
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeVMFEntity *pNode = CastElement< CDmeVMFEntity >( entities[ i ] );
+ Vector &vecAngles = *(Vector*)(&pNode->GetRenderAngles());
+ if ( pNode->GetRenderOrigin().DistTo( vecOrigin ) < 1e-3 && vecAngles.DistTo( *(Vector*)&angAbsAngles ) < 1e-1 )
+ return pNode;
+ }
+
+ return NULL;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &vecStart -
+// &vecEnd -
+// Output : CDmeVMFEntity
+//-----------------------------------------------------------------------------
+CDmeVMFEntity *CVcdBlockDoc::GetInfoTargetForLocation( Vector &vecStart, Vector &vecEnd )
+{
+ Vector vecDelta;
+ float flEndDist;
+
+ vecDelta = vecEnd - vecStart;
+ flEndDist = VectorNormalize( vecDelta );
+
+ CDmeVMFEntity *pSelectedNode = NULL;
+ float flMinDistFromLine = 1E30;
+
+ const CDmrElementArray<CDmElement> entities = GetEntityList();
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeVMFEntity *pNode = CastElement< CDmeVMFEntity >( entities[ i ] );
+ float flDistAway = DotProduct( pNode->GetRenderOrigin() - vecStart, vecDelta );
+
+ if (flDistAway > 0.0 && flDistAway < flEndDist)
+ {
+ float flDistFromLine = (pNode->GetRenderOrigin() - vecStart - vecDelta * flDistAway).Length();
+ if (flDistFromLine < flMinDistFromLine)
+ {
+ pSelectedNode = pNode;
+ flMinDistFromLine = flDistFromLine;
+ }
+ }
+ }
+ return pSelectedNode;
+}
+
+
+//-----------------------------------------------------------------------------
+// Populate string choice lists
+//-----------------------------------------------------------------------------
+bool CVcdBlockDoc::GetStringChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, StringChoiceList_t &list )
+{
+ if ( !Q_stricmp( pChoiceListType, "info_targets" ) )
+ {
+ const CDmrElementArray<> entities = GetEntityList();
+
+ StringChoice_t sChoice;
+ sChoice.m_pValue = "";
+ sChoice.m_pChoiceString = "";
+ list.AddToTail( sChoice );
+
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeVMFEntity *pNode = CastElement< CDmeVMFEntity >( entities[ i ] );
+ if ( !V_stricmp( pNode->GetClassName(), "info_target" ) )
+ {
+ StringChoice_t sChoice;
+ sChoice.m_pValue = pNode->GetTargetName();
+ sChoice.m_pChoiceString = pNode->GetTargetName();
+ list.AddToTail( sChoice );
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Populate element choice lists
+//-----------------------------------------------------------------------------
+bool CVcdBlockDoc::GetElementChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, ElementChoiceList_t &list )
+{
+ if ( !Q_stricmp( pChoiceListType, "allelements" ) )
+ {
+ AddElementsRecursively( m_hEditRoot, list );
+ return true;
+ }
+
+ if ( !Q_stricmp( pChoiceListType, "info_targets" ) )
+ {
+ const CDmrElementArray<> entities = GetEntityList();
+
+ bool bFound = false;
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeVMFEntity *pNode = CastElement< CDmeVMFEntity >( entities[ i ] );
+ if ( !V_stricmp( pNode->GetClassName(), "info_target" ) )
+ {
+ bFound = true;
+ ElementChoice_t sChoice;
+ sChoice.m_pValue = pNode;
+ sChoice.m_pChoiceString = pNode->GetTargetName();
+ list.AddToTail( sChoice );
+ }
+ }
+ return bFound;
+ }
+
+ // by default, try to treat the choice list type as a Dme element type
+ AddElementsRecursively( m_hEditRoot, list, pChoiceListType );
+
+ return list.Count() > 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when data changes
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ SetDirty( nNotifyFlags & NOTIFY_SETDIRTYFLAG ? true : false );
+ m_pCallback->OnDocChanged( pReason, nNotifySource, nNotifyFlags );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// List of all entity classnames to copy over from the original block
+//-----------------------------------------------------------------------------
+static const char *s_pUseOriginalClasses[] =
+{
+ "worldspawn",
+ "func_occluder",
+ NULL
+};
+
+
+//-----------------------------------------------------------------------------
+// The server just loaded, populate the list with the entities is has
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::ServerLevelInitPostEntity( void )
+{
+ CDmrElementArray<> entityList = GetEntityList();
+
+ if ( entityList.Count() )
+ {
+ VerifyAllEdits( entityList );
+ }
+ else
+ {
+ InitializeFromServer( entityList );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Create a list of entities based on what the server has
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::InitializeFromServer( CDmrElementArray<> &entityList )
+{
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Initialize From Server" );
+
+ entityList.RemoveAll();
+
+ // initialize list with entities on the server
+ CBaseEntity *pServerEnt = servertools->FirstEntity();
+ while (pServerEnt)
+ {
+ char classname[256];
+
+ if (servertools->GetKeyValue( pServerEnt, "classname", classname, sizeof( classname ) ) )
+ {
+ if ( !Q_stricmp( classname, "info_target" ))
+ {
+ char hammerid[256];
+ if ( servertools->GetKeyValue( pServerEnt, "hammerid", hammerid, sizeof( hammerid ) ) )
+ {
+ int nextId = CDmeVMFEntity::GetNextEntityId();
+ CDmeVMFEntity::SetNextEntityId( atoi( hammerid ) );
+
+ CDmeVMFEntity *pTarget = CreateElement<CDmeVMFEntity>( "", entityList.GetOwner()->GetFileId() );
+
+ CDmeVMFEntity::SetNextEntityId( nextId );
+
+ if ( pTarget->CopyFromServer( pServerEnt ) )
+ {
+ entityList.AddToTail( pTarget );
+ }
+ }
+ }
+ }
+ pServerEnt = servertools->NextEntity( pServerEnt );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Check the list of entities on the server against the edits that are already made
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::VerifyAllEdits( const CDmrElementArray<> &entityList )
+{
+ // already filled in
+ for (int i = 0; i < entityList.Count(); i++)
+ {
+ CDmeVMFEntity *pEntity = CastElement<CDmeVMFEntity>( entityList[i] );
+
+ CBaseEntity *pServerEntity = servertools->FindEntityByHammerID( pEntity->GetEntityId() );
+
+ if (pServerEntity != NULL)
+ {
+ if (!pEntity->IsSameOnServer( pServerEntity ))
+ {
+ pEntity->MarkDirty();
+ }
+ else
+ {
+ pEntity->MarkDirty(false);
+ }
+ }
+ else
+ {
+ pEntity->CreateOnServer();
+ pEntity->MarkDirty();
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Load the VMF file, merge in all the edits, write it back out
+//-----------------------------------------------------------------------------
+bool CVcdBlockDoc::CopyEditsToVMF( )
+{
+ const CDmrElementArray<CDmElement> entityList = GetEntityList();
+
+ CDmElement *pVMF = NULL;
+ DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( m_pVMFFileName );
+ if ( g_pDataModel->RestoreFromFile( m_pVMFFileName, NULL, "vmf", &pVMF ) == DMFILEID_INVALID )
+ {
+ // needs some kind of error message
+ return false;
+ }
+
+ CDmrElementArray<CDmElement> vmfEntities( pVMF, "entities" );
+
+ int nVMFCount = vmfEntities.Count();
+ for (int i = 0; i < nVMFCount; i++)
+ {
+ CDmElement *pVMFEntity = vmfEntities[i];
+
+ char classname[256];
+ pVMFEntity->GetValueAsString( "classname", classname, sizeof( classname ) );
+
+ if ( Q_stricmp( "info_target", classname ) )
+ continue;
+
+ int nHammerID = atoi( pVMFEntity->GetName() );
+
+ // find a match.
+ int nCount = entityList.Count();
+ for (int j = 0; j < nCount; j++)
+ {
+ CDmeVMFEntity *pEntity = CastElement<CDmeVMFEntity>( entityList[j] );
+
+ if ( pEntity->IsDirty() && pEntity->GetEntityId() == nHammerID)
+ {
+ char text[256];
+ pEntity->GetValueAsString( "targetname", text, sizeof( text ) );
+ pVMFEntity->SetValueFromString( "targetname", text );
+ pEntity->GetValueAsString( "origin", text, sizeof( text ) );
+ pVMFEntity->SetValueFromString( "origin", text );
+ pEntity->GetValueAsString( "angles", text, sizeof( text ) );
+ pVMFEntity->SetValueFromString( "angles", text );
+
+ pEntity->MarkDirty(false);
+ }
+ }
+ }
+
+ // add the new entities
+ int nCount = entityList.Count();
+ for (int j = 0; j < nCount; j++)
+ {
+ CDmeVMFEntity *pEntity = CastElement<CDmeVMFEntity>( entityList[j] );
+
+ if ( pEntity->IsDirty())
+ {
+ CDmElement *pVMFEntity = CreateElement<CDmElement>( pEntity->GetName(), fileid );
+
+ char text[256];
+ pEntity->GetValueAsString( "classname", text, sizeof( text ) );
+ pVMFEntity->SetValue( "classname", text );
+ pEntity->GetValueAsString( "targetname", text, sizeof( text ) );
+ pVMFEntity->SetValue( "targetname", text );
+ pEntity->GetValueAsString( "origin", text, sizeof( text ) );
+ pVMFEntity->SetValue( "origin", text );
+ pEntity->GetValueAsString( "angles", text, sizeof( text ) );
+ pVMFEntity->SetValue( "angles", text );
+
+ vmfEntities.AddToTail( pVMFEntity );
+
+ pEntity->MarkDirty(false);
+ }
+ }
+
+ // currently, don't overwrite the vmf, not sure if this is serializing correctly yet
+ char tmpname[ 256 ];
+ Q_StripExtension( m_pVMFFileName, tmpname, sizeof(tmpname) );
+ Q_SetExtension( tmpname, ".vme", sizeof(tmpname) );
+
+ if (!g_pDataModel->SaveToFile( tmpname, NULL, "keyvalues", "vmf", pVMF ))
+ {
+ // needs some kind of error message
+ return false;
+ }
+
+ /*
+ // If we successfully read the file in, ask it for the max hammer id
+ int nMaxHammerId = pVMF->GetAttributeValue<int>( "maxHammerId" );
+ CDmeVMFEntity::SetNextEntityId( nMaxHammerId + 1 );
+ m_hVMFRoot = pVMF;
+ */
+
+ return true;
+}
+
+
+bool CVcdBlockDoc::RememberPlayerPosition()
+{
+ return true;
+}
diff --git a/tools/vcdblock/vcdblockdoc.h b/tools/vcdblock/vcdblockdoc.h
new file mode 100644
index 0000000..51d6293
--- /dev/null
+++ b/tools/vcdblock/vcdblockdoc.h
@@ -0,0 +1,108 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef VCDBLOCKDOC_H
+#define VCDBLOCKDOC_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "dme_controls/inotifyui.h"
+#include "datamodel/dmehandle.h"
+#include "datamodel/dmelement.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class IVcdBlockDocCallback;
+class CVcdBlockDoc;
+class CDmeVMFEntity;
+
+
+//-----------------------------------------------------------------------------
+// Contains all editable state
+//-----------------------------------------------------------------------------
+class CVcdBlockDoc : public IDmNotify
+{
+public:
+ CVcdBlockDoc( IVcdBlockDocCallback *pCallback );
+ ~CVcdBlockDoc();
+
+ // Inherited from INotifyUI
+ virtual void NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Sets/Gets the file name
+ const char *GetBSPFileName();
+ const char *GetVMFFileName();
+ const char *GetEditFileName();
+ void SetVMFFileName( const char *pFileName );
+ void SetEditFileName( const char *pFileName );
+
+ // Dirty bits (has it changed since the last time it was saved?)
+ void SetDirty( bool bDirty );
+ bool IsDirty() const;
+
+ // Saves/loads from file
+ bool LoadFromFile( const char *pFileName );
+ void SaveToFile( );
+
+ // Returns the root object
+ CDmElement *GetRootObject();
+
+ // Called when data changes (see INotifyUI for flags)
+ void OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Create a text block the engine can parse containing the entity data to spawn
+ void ServerLevelInitPostEntity( void );
+
+ // Returns the entity list
+ CDmAttribute *GetEntityList();
+
+ // Adds a new info_target
+ void AddNewInfoTarget( void );
+ void AddNewInfoTarget( const Vector &vecOrigin, const QAngle &angAngles );
+
+ // Deletes a commentary node
+ void DeleteInfoTarget( CDmeVMFEntity *pNode );
+
+ // Returns the commentary node at the specified location
+ CDmeVMFEntity *GetInfoTargetForLocation( Vector &vecOrigin, QAngle &angAbsAngles );
+
+ // Returns the info target that's closest to this line
+ CDmeVMFEntity *GetInfoTargetForLocation( Vector &vecStart, Vector &vecEnd );
+
+ // For element choice lists. Return false if it's an unknown choice list type
+ virtual bool GetStringChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, StringChoiceList_t &list );
+ virtual bool GetElementChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, ElementChoiceList_t &list );
+
+
+ void VerifyAllEdits( const CDmrElementArray<> &entityList );
+ void InitializeFromServer( CDmrElementArray<> &entityList );
+
+ bool CopyEditsToVMF( void );
+
+ bool RememberPlayerPosition( void );
+
+private:
+ IVcdBlockDocCallback *m_pCallback;
+ CDmeHandle< CDmElement > m_hVMFRoot; // VMF file
+ CDmeHandle< CDmElement > m_hEditRoot; // VMF Edits file
+ char m_pBSPFileName[512];
+ char m_pVMFFileName[512];
+ char m_pEditFileName[512];
+ bool m_bDirty;
+};
+
+
+
+#endif // VCDBLOCKDOC_H
diff --git a/tools/vcdblock/vcdblocktool.cpp b/tools/vcdblock/vcdblocktool.cpp
new file mode 100644
index 0000000..b9a143f
--- /dev/null
+++ b/tools/vcdblock/vcdblocktool.cpp
@@ -0,0 +1,1300 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core Movie Maker UI API
+//
+//=============================================================================
+
+#include "vcdblocktool.h"
+#include "vgui_controls/Menu.h"
+#include "tier1/KeyValues.h"
+#include "vgui/IInput.h"
+#include "vgui/KeyCode.h"
+#include "vgui_controls/FileOpenDialog.h"
+#include "filesystem.h"
+#include "vgui/ilocalize.h"
+#include "tier0/icommandline.h"
+#include "materialsystem/imaterialsystem.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "vcdblockdoc.h"
+#include "infotargetbrowserpanel.h"
+#include "infotargetpropertiespanel.h"
+#include "dme_controls/AttributeStringChoicePanel.h"
+#include "tier3/tier3.h"
+#include "tier2/fileutils.h"
+#include "vgui/ivgui.h"
+#include "view_shared.h"
+
+// for tracing
+#include "cmodel.h"
+#include "engine/ienginetrace.h"
+
+using namespace vgui;
+
+
+const char *GetVGuiControlsModuleName()
+{
+ return "VcdBlockTool";
+}
+
+//-----------------------------------------------------------------------------
+// Connect, disconnect
+//-----------------------------------------------------------------------------
+bool ConnectTools( CreateInterfaceFn factory )
+{
+ return (materials != NULL) && (g_pMatSystemSurface != NULL) && (mdlcache != NULL) &&
+ (studiorender != NULL) && (g_pMaterialSystemHardwareConfig != NULL);
+}
+
+void DisconnectTools( )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Singleton
+//-----------------------------------------------------------------------------
+CVcdBlockTool *g_pVcdBlockTool = NULL;
+
+void CreateTools()
+{
+ g_pVcdBlockTool = new CVcdBlockTool();
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CVcdBlockTool::CVcdBlockTool()
+{
+ m_bInNodeDropMode = false;
+ m_pMenuBar = NULL;
+ m_pDoc = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Init, shutdown
+//-----------------------------------------------------------------------------
+bool CVcdBlockTool::Init( )
+{
+ m_pDoc = NULL;
+ m_RecentFiles.LoadFromRegistry( GetRegistryName() );
+
+ // NOTE: This has to happen before BaseClass::Init
+ g_pVGuiLocalize->AddFile( "resource/toolvcdblock_%language%.txt" );
+
+ if ( !BaseClass::Init( ) )
+ return false;
+
+ {
+ m_hPreviewTarget = CreateElement<CDmeVMFEntity>( "preview target", DMFILEID_INVALID );
+ m_hPreviewTarget->SetValue( "classname", "info_target" );
+ }
+
+ return true;
+}
+
+void CVcdBlockTool::Shutdown()
+{
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ g_pDataModel->DestroyElement( m_hPreviewTarget );
+
+ BaseClass::Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// returns the document
+//-----------------------------------------------------------------------------
+inline CVcdBlockDoc *CVcdBlockTool::GetDocument()
+{
+ return m_pDoc;
+}
+
+
+//-----------------------------------------------------------------------------
+// Tool activation/deactivation
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnToolActivate()
+{
+ BaseClass::OnToolActivate();
+
+ enginetools->Command( "commentary 1\n" );
+}
+
+void CVcdBlockTool::OnToolDeactivate()
+{
+ BaseClass::OnToolDeactivate();
+
+ enginetools->Command( "commentary 0\n" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Enter mode where we preview dropping nodes
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::EnterTargetDropMode()
+{
+ // Can only do it in editor mode
+ if ( IsGameInputEnabled() )
+ return;
+
+ m_bInNodeDropMode = true;
+ SetMode( true, IsFullscreen() );
+ {
+ CDisableUndoScopeGuard guard;
+ m_hPreviewTarget->DrawInEngine( true );
+ }
+ SetMiniViewportText( "Left Click To Place Info Target\nESC to exit" );
+ enginetools->Command( "noclip\n" );
+}
+
+void CVcdBlockTool::LeaveTargetDropMode()
+{
+ Assert( m_bInNodeDropMode );
+
+ m_bInNodeDropMode = false;
+ SetMode( false, IsFullscreen() );
+ {
+ CDisableUndoScopeGuard guard;
+ m_hPreviewTarget->DrawInEngine( false );
+ }
+ SetMiniViewportText( NULL );
+ enginetools->Command( "noclip\n" );
+}
+
+
+//-----------------------------------------------------------------------------
+// figure out if the click is in the miniviewport, and where it's aiming
+//-----------------------------------------------------------------------------
+bool CVcdBlockTool::IsMiniViewportCursor( int x, int y, Vector &org, Vector &forward )
+{
+ // when dealing with the miniviewport, it just wants the screen area
+ int minx, miny, width, height;
+ GetMiniViewportEngineBounds( minx, miny, width, height );
+ x = x - minx;
+ y = y - miny;
+ if (x >= 0 && x < width && y >= 0 && y < height)
+ {
+ CViewSetup view;
+ if (enginetools->GetPlayerView( view, 0, 0, width, height ))
+ {
+ // get a ray into the world
+ enginetools->CreatePickingRay( view, x, y, org, forward );
+ return true;
+ }
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::QuickLoad( void )
+{
+ m_bHasPlayerPosition = true;
+ float flFov;
+ clienttools->GetLocalPlayerEyePosition( m_vecPlayerOrigin, m_vecPlayerAngles, flFov );
+
+ enginetools->Command( "load quick\n" );
+ enginetools->Execute( );
+}
+
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::QuickSave( void )
+{
+ enginetools->Command( "save quick\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Gets the position of the preview object
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::GetPlacementInfo( Vector &vecOrigin, QAngle &angAngles )
+{
+ // Places the placement objects
+ float flFov;
+ clienttools->GetLocalPlayerEyePosition( vecOrigin, angAngles, flFov );
+
+ Vector vecForward;
+ AngleVectors( angAngles, &vecForward );
+ VectorMA( vecOrigin, 40.0f, vecForward, vecOrigin );
+
+ // Eliminate pitch
+ angAngles.x = 0.0f;
+}
+
+
+//-----------------------------------------------------------------------------
+// Place the preview object before rendering
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::ClientPreRender()
+{
+ BaseClass::ClientPreRender();
+ if ( !m_bInNodeDropMode )
+ return;
+
+ // Places the placement objects
+ Vector vecOrigin;
+ QAngle angAngles;
+ GetPlacementInfo( vecOrigin, angAngles );
+
+ CDisableUndoScopeGuard guard;
+ m_hPreviewTarget->SetRenderOrigin( vecOrigin );
+ m_hPreviewTarget->SetRenderAngles( angAngles );
+}
+
+
+//-----------------------------------------------------------------------------
+// Let tool override key events (ie ESC and ~)
+//-----------------------------------------------------------------------------
+bool CVcdBlockTool::TrapKey( ButtonCode_t key, bool down )
+{
+ // Don't hook keyboard if not topmost
+ if ( !IsActiveTool() )
+ return false; // didn't trap, continue processing
+
+ // Don't hook these methods if the game isn't running
+ if ( !enginetools->IsInGame() )
+ return false;
+
+ if ( !m_bInNodeDropMode )
+ {
+ if ( key == MOUSE_LEFT )
+ {
+ if ( m_bInNodeDragMode && down == false )
+ {
+ m_bInNodeDragMode = false;
+ }
+ else if ( !m_bInNodeDragMode && down == true )
+ {
+ int x, y;
+ input()->GetCursorPos(x, y);
+
+ Vector org, forward;
+ if (IsMiniViewportCursor( x, y, org, forward ))
+ {
+ // trace to something solid
+ Ray_t ray;
+ CTraceFilterWorldAndPropsOnly traceFilter;
+ CBaseTrace tr;
+ ray.Init( org, org + forward * 1000.0 );
+ enginetools->TraceRayServer( ray, MASK_OPAQUE, &traceFilter, &tr );
+
+#if 1
+ CDmeVMFEntity *pSelection = m_pDoc->GetInfoTargetForLocation( tr.startpos, tr.endpos );
+ if (pSelection)
+ {
+ GetInfoTargetBrowser()->SelectNode( pSelection );
+ m_bInNodeDragMode = true;
+ m_iDragX = x;
+ m_iDragY = y;
+ return true;
+ }
+#else
+ if (tr.fraction < 1.0f)
+ {
+ // needs a better angle initialization
+ Vector vecOrigin;
+ QAngle angAngles;
+ GetPlacementInfo( vecOrigin, angAngles );
+ m_pDoc->AddNewInfoTarget( tr.endpos, angAngles );
+ return true; // trapping this key, stop processing
+ }
+#endif
+ }
+ }
+ }
+ return BaseClass::TrapKey( key, down );
+ }
+
+ if ( !down )
+ return false;
+
+ if ( key == KEY_ESCAPE )
+ {
+ LeaveTargetDropMode();
+ return true; // trapping this key, stop processing
+ }
+
+ if ( key == MOUSE_LEFT )
+ {
+ Vector vecOrigin;
+ QAngle angAngles;
+ GetPlacementInfo( vecOrigin, angAngles );
+ m_pDoc->AddNewInfoTarget( vecOrigin, angAngles );
+ return true; // trapping this key, stop processing
+ }
+
+ return false; // didn't trap, continue processing
+}
+
+
+//-----------------------------------------------------------------------------
+// Used to hook DME VMF entities into the render lists
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::DrawEntitiesInEngine( bool bDrawInEngine )
+{
+ if ( !m_pDoc )
+ return;
+
+ const CDmrElementArray<CDmElement> entities( m_pDoc->GetEntityList() );
+ if ( !entities.IsValid() )
+ return;
+
+ CDisableUndoScopeGuard guard;
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeVMFEntity *pEntity = CastElement<CDmeVMFEntity>( entities[i] );
+ Assert( pEntity );
+ pEntity->DrawInEngine( bDrawInEngine );
+ }
+}
+
+void CVcdBlockTool::ClientLevelInitPostEntity()
+{
+ BaseClass::ClientLevelInitPostEntity();
+ DrawEntitiesInEngine( true );
+
+ AttachAllEngineEntities();
+}
+
+void CVcdBlockTool::ClientLevelShutdownPreEntity()
+{
+ DrawEntitiesInEngine( false );
+ BaseClass::ClientLevelShutdownPreEntity();
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get a new scheme to be applied to this tool
+//-----------------------------------------------------------------------------
+vgui::HScheme CVcdBlockTool::GetToolScheme()
+{
+ return vgui::scheme()->LoadSchemeFromFile( "Resource/BoxRocket.res", "BoxRocket" );
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// The View menu
+//
+//-----------------------------------------------------------------------------
+class CVcdBlockViewMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CVcdBlockViewMenuButton, CToolMenuButton );
+public:
+ CVcdBlockViewMenuButton( CVcdBlockTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+
+private:
+ CVcdBlockTool *m_pTool;
+};
+
+CVcdBlockViewMenuButton::CVcdBlockViewMenuButton( CVcdBlockTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ m_pTool = parent;
+
+ AddCheckableMenuItem( "properties", "#VcdBlockProperties", new KeyValues( "OnToggleProperties" ), pActionSignalTarget );
+ AddCheckableMenuItem( "entityreport", "#VcdBlockEntityReport", new KeyValues( "O|�glaEq��pyOeport" ), pActionSignalTarget );
+
+ AddSeparator();
+
+ AddMenuItem( "defaultlayout", "#VcdBlockViewDefault", new KeyValues( "OnDefaultLayout" ), pActionSignalTarget );
+
+ SetMenu(m_pMenu);
+}
+
+void CVcdBlockViewMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ int id;
+
+ CVcdBlockDoc *pDoc = m_pTool->GetDocument();
+ if ( pDoc )
+ {
+ id = m_Items.Find( "properties" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ Panel *p;
+ p = m_pTool->GetProperties();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+
+ id = m_Items.Find( "entityreport" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ p = m_pTool->GetInfoTargetBrowser();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+ }
+ else
+ {
+ id = m_Items.Find( "properties" );
+ m_pMenu->SetItemEnabled( id, false );
+ id = m_Items.Find( "entityreport" );
+ m_pMenu->SetItemEnabled( id, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// The Tool menu
+//
+//-----------------------------------------------------------------------------
+class CVcdBlockToolMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CVcdBlockToolMenuButton, CToolMenuButton );
+public:
+ CVcdBlockToolMenuButton( CVcdBlockTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+
+private:
+ CVcdBlockTool *m_pTool;
+};
+
+CVcdBlockToolMenuButton::CVcdBlockToolMenuButton( CVcdBlockTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ m_pTool = parent;
+
+ AddMenuItem( "addnewnodes", "#VcdBlockAddNewNodes", new KeyValues( "AddNewNodes" ), pActionSignalTarget, NULL, "VcdBlockAddNewNodes" );
+ AddMenuItem( "copyeditstovmf", "#VcdBlockCopyEditsToVMF", new KeyValues( "CopyEditsToVMF" ), pActionSignalTarget, NULL, "VcdBlockCopyEditsToVMF" );
+
+ AddSeparator();
+
+ AddCheckableMenuItem( "rememberposition", "#VcdBlockRememberPosition", new KeyValues( "RememberPosition" ), pActionSignalTarget, NULL, "VcdBlockRememberPosition" );
+
+ SetMenu(m_pMenu);
+}
+
+void CVcdBlockToolMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ int id;
+
+ CVcdBlockDoc *pDoc = m_pTool->GetDocument();
+
+ id = m_Items.Find( "addnewnodes" );
+ m_pMenu->SetItemEnabled( id, pDoc != NULL );
+
+ id = m_Items.Find( "rememberposition" );
+ m_pMenu->SetMenuItemChecked( id, m_pTool->GetRememberPlayerPosition() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the menu bar
+//-----------------------------------------------------------------------------
+vgui::MenuBar *CVcdBlockTool::CreateMenuBar( CBaseToolSystem *pParent )
+{
+ m_pMenuBar = new CToolFileMenuBar( pParent, "Main Menu Bar" );
+
+ // Sets info in the menu bar
+ char title[ 64 ];
+ ComputeMenuBarTitle( title, sizeof( title ) );
+ m_pMenuBar->SetInfo( title );
+ m_pMenuBar->SetToolName( GetToolName() );
+
+ // Add menu buttons
+ CToolMenuButton *pFileButton = CreateToolFileMenuButton( m_pMenuBar, "File", "&File", GetActionTarget(), this );
+ CToolMenuButton *pEditButton = CreateToolEditMenuButton( this, "Edit", "&Edit", GetActionTarget() );
+ CVcdBlockToolMenuButton *pToolButton = new CVcdBlockToolMenuButton( this, "VcdBlock", "&VcdBlock", GetActionTarget() );
+ CVcdBlockViewMenuButton *pViewButton = new CVcdBlockViewMenuButton( this, "View", "&View", GetActionTarget() );
+ CToolMenuButton *pSwitchButton = CreateToolSwitchMenuButton( m_pMenuBar, "Switcher", "&Tools", GetActionTarget() );
+
+ m_pMenuBar->AddButton( pFileButton );
+ m_pMenuBar->AddButton( pEditButton );
+ m_pMenuBar->AddButton( pToolButton );
+ m_pMenuBar->AddButton( pViewButton );
+ m_pMenuBar->AddButton( pSwitchButton );
+
+ return m_pMenuBar;
+}
+
+
+//-----------------------------------------------------------------------------
+// Updates the menu bar based on the current file
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::UpdateMenuBar( )
+{
+ if ( !m_pDoc )
+ {
+ m_pMenuBar->SetFileName( "#VcdBlockNoFile" );
+ return;
+ }
+
+ const char *pEditFile = m_pDoc->GetEditFileName();
+ if ( !pEditFile[0] )
+ {
+ m_pMenuBar->SetFileName( "#VcdBlockNoFile" );
+ return;
+ }
+
+ if ( m_pDoc->IsDirty() )
+ {
+ char sz[ 512 ];
+ Q_snprintf( sz, sizeof( sz ), "* %s", pEditFile );
+ m_pMenuBar->SetFileName( sz );
+ }
+ else
+ {
+ m_pMenuBar->SetFileName( pEditFile );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets at tool windows
+//-----------------------------------------------------------------------------
+CInfoTargetPropertiesPanel *CVcdBlockTool::GetProperties()
+{
+ return m_hProperties.Get();
+}
+
+CInfoTargetBrowserPanel *CVcdBlockTool::GetInfoTargetBrowser()
+{
+ return m_hInfoTargetBrowser.Get();
+}
+
+
+//-----------------------------------------------------------------------------
+// Shows element properties
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::ShowElementProperties( )
+{
+ if ( !m_pDoc )
+ return;
+
+ // It should already exist
+ Assert( m_hProperties.Get() );
+ if ( m_hProperties.Get() )
+ {
+ m_hProperties->SetObject( m_hCurrentEntity );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Destroys all tool windows
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::ShowEntityInEntityProperties( CDmeVMFEntity *pEntity )
+{
+ Assert( m_hProperties.Get() );
+ m_hCurrentEntity = pEntity;
+ m_hProperties->SetObject( m_hCurrentEntity );
+}
+
+
+//-----------------------------------------------------------------------------
+// Destroys all tool windows
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::DestroyToolContainers()
+{
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets up the default layout
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnDefaultLayout()
+{
+ int y = m_pMenuBar->GetTall();
+
+ int usew, useh;
+ GetSize( usew, useh );
+
+ DestroyToolContainers();
+
+ Assert( ToolWindow::GetToolWindowCount() == 0 );
+
+ CInfoTargetPropertiesPanel *properties = GetProperties();
+ CInfoTargetBrowserPanel *pEntityReport = GetInfoTargetBrowser();
+
+ // Need three containers
+ ToolWindow *pPropertyWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, properties, "#VcdBlockProperties", false );
+ ToolWindow *pEntityReportWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, pEntityReport, "#VcdBlockEntityReport", false );
+
+ int halfScreen = usew / 2;
+ int bottom = useh - y;
+ int sy = (bottom - y) / 2;
+ SetMiniViewportBounds( halfScreen, y, halfScreen, sy - y );
+ pEntityReportWindow->SetBounds( 0, y, halfScreen, bottom );
+ pPropertyWindow->SetBounds( halfScreen, sy, halfScreen, bottom - sy );
+}
+
+void CVcdBlockTool::OnToggleProperties()
+{
+ if ( m_hProperties.Get() )
+ {
+ ToggleToolWindow( m_hProperties.Get(), "#VcdBlockProperties" );
+ }
+}
+
+void CVcdBlockTool::OnToggleEntityReport()
+{
+ if ( m_hInfoTargetBrowser.Get() )
+ {
+ ToggleToolWindow( m_hInfoTargetBrowser.Get(), "#VcdBlockEntityReport" );
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Creates
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::CreateTools( CVcdBlockDoc *doc )
+{
+ if ( !m_hProperties.Get() )
+ {
+ m_hProperties = new CInfoTargetPropertiesPanel( m_pDoc, this );
+ }
+
+ if ( !m_hInfoTargetBrowser.Get() )
+ {
+ m_hInfoTargetBrowser = new CInfoTargetBrowserPanel( m_pDoc, this, "InfoTargetBrowserPanel" );
+ }
+
+ RegisterToolWindow( m_hProperties );
+ RegisterToolWindow( m_hInfoTargetBrowser );
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the tools
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::InitTools()
+{
+ ShowElementProperties();
+
+ // FIXME: There are no tool windows here; how should this work?
+ // These panels are saved
+ windowposmgr->RegisterPanel( "properties", m_hProperties, false );
+ windowposmgr->RegisterPanel( "entityreport", m_hInfoTargetBrowser, false );
+
+ if ( !windowposmgr->LoadPositions( "cfg/vcdblock.txt", this, &m_ToolWindowFactory, "VcdBlock" ) )
+ {
+ OnDefaultLayout();
+ }
+}
+
+
+void CVcdBlockTool::DestroyTools()
+{
+ m_hCurrentEntity = NULL;
+
+ if ( m_hProperties.Get() && m_hInfoTargetBrowser.Get() )
+ {
+ windowposmgr->SavePositions( "cfg/vcdblock.txt", "VcdBlock" );
+ }
+
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+
+ UnregisterAllToolWindows();
+
+ if ( m_hProperties.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hProperties.Get() );
+ delete m_hProperties.Get();
+ m_hProperties = NULL;
+ }
+
+ if ( m_hInfoTargetBrowser.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hInfoTargetBrowser.Get() );
+ delete m_hInfoTargetBrowser.Get();
+ m_hInfoTargetBrowser = NULL;
+ }
+}
+
+
+void CVcdBlockTool::ShowToolWindow( Panel *tool, char const *toolName, bool visible )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL && visible )
+ {
+ m_ToolWindowFactory.InstanceToolWindow( this, false, tool, toolName, false );
+ }
+ else if ( !visible )
+ {
+ ToolWindow *tw = dynamic_cast< ToolWindow * >( tool->GetParent()->GetParent() );
+ Assert( tw );
+ tw->RemovePage( tool );
+ }
+}
+
+void CVcdBlockTool::ToggleToolWindow( Panel *tool, char const *toolName )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL )
+ {
+ ShowToolWindow( tool, toolName, true );
+ }
+ else
+ {
+ ShowToolWindow( tool, toolName, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates the action menu
+//-----------------------------------------------------------------------------
+vgui::Menu *CVcdBlockTool::CreateActionMenu( vgui::Panel *pParent )
+{
+ vgui::Menu *pActionMenu = new Menu( pParent, "ActionMenu" );
+ pActionMenu->AddMenuItem( "#ToolHide", new KeyValues( "Command", "command", "HideActionMenu" ), GetActionTarget() );
+ return pActionMenu;
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from IFileMenuCallbacks
+//-----------------------------------------------------------------------------
+int CVcdBlockTool::GetFileMenuItemsEnabled( )
+{
+ int nFlags = FILE_ALL;
+ if ( m_RecentFiles.IsEmpty() )
+ {
+ nFlags &= ~(FILE_RECENT | FILE_CLEAR_RECENT);
+ }
+ return nFlags;
+}
+
+void CVcdBlockTool::AddRecentFilesToMenu( vgui::Menu *pMenu )
+{
+ m_RecentFiles.AddToMenu( pMenu, GetActionTarget(), "OnRecent" );
+}
+
+bool CVcdBlockTool::GetPerforceFileName( char *pFileName, int nMaxLen )
+{
+ if ( !m_pDoc )
+ return false;
+
+ Q_strncpy( pFileName, m_pDoc->GetEditFileName(), nMaxLen );
+ return pFileName[0] != 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnExit()
+{
+ enginetools->Command( "quit\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Handle commands from the action menu and other menus
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnCommand( const char *cmd )
+{
+ if ( !V_stricmp( cmd, "HideActionMenu" ) )
+ {
+ if ( GetActionMenu() )
+ {
+ GetActionMenu()->SetVisible( false );
+ }
+ }
+ else if ( const char *pSuffix = StringAfterPrefix( cmd, "OnRecent" ) )
+ {
+ int idx = Q_atoi( pSuffix );
+ OpenFileFromHistory( idx );
+ }
+ else if( const char *pSuffix = StringAfterPrefix( cmd, "OnTool" ) )
+ {
+ int idx = Q_atoi( pSuffix );
+ enginetools->SwitchToTool( idx );
+ }
+ else if ( !V_stricmp( cmd, "OnUndo" ) )
+ {
+ OnUndo();
+ }
+ else if ( !V_stricmp( cmd, "OnRedo" ) )
+ {
+ OnRedo();
+ }
+ else if ( !V_stricmp( cmd, "OnDescribeUndo" ) )
+ {
+ OnDescribeUndo();
+ }
+ else
+ {
+ BaseClass::OnCommand( cmd );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Command handlers
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnNew()
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetEditFileName();
+ }
+
+ // Bring up the file open dialog to choose a .bsp file
+ OpenFile( "bsp", pSaveFileName, "vle", nFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when the File->Open menu is selected
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnOpen( )
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetEditFileName();
+ }
+
+ OpenFile( "vle", pSaveFileName, "vle", nFlags );
+}
+
+
+bool CVcdBlockTool::OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ OnCloseNoSave();
+
+ if ( !LoadDocument( pFileName ) )
+ return false;
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ UpdateMenuBar();
+ return true;
+}
+
+void CVcdBlockTool::Save()
+{
+ if ( m_pDoc )
+ {
+ SaveFile( m_pDoc->GetEditFileName(), "vle", FOSM_SHOW_PERFORCE_DIALOGS );
+ }
+}
+
+void CVcdBlockTool::OnSaveAs()
+{
+ if ( m_pDoc )
+ {
+ SaveFile( NULL, "vle", FOSM_SHOW_PERFORCE_DIALOGS );
+ }
+}
+
+void CVcdBlockTool::OnRestartLevel()
+{
+ // FIXME: We may want to use this instead of completely restarting,
+ // but it's less well tested. Should be a lot faster though
+
+ // Reloads the map, entities only, will reload every entity
+ // enginetools->Command( "respawn_entities\n" );
+ enginetools->Command( "restart" );
+ enginetools->Execute();
+
+ const CDmrElementArray<> entities = m_pDoc->GetEntityList();
+ if ( !entities.IsValid() )
+ return;
+
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeVMFEntity *pEntity = CastElement<CDmeVMFEntity>( entities[i] );
+ Assert( pEntity );
+ pEntity->MarkDirty( false );
+ }
+}
+
+void CVcdBlockTool::SaveAndTest()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetEditFileName(), "vle", FOSM_SHOW_PERFORCE_DIALOGS,
+ new KeyValues( "RestartLevel" ) );
+ }
+ else
+ {
+ OnRestartLevel();
+ }
+}
+
+void CVcdBlockTool::RestartMap()
+{
+ OnRestartLevel();
+}
+
+bool CVcdBlockTool::OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ if ( !m_pDoc )
+ return true;
+
+ m_pDoc->SetEditFileName( pFileName );
+ m_pDoc->SaveToFile( );
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ UpdateMenuBar();
+ return true;
+}
+
+void CVcdBlockTool::OnClose()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetEditFileName(), "vle", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnClose" ) );
+ return;
+ }
+
+ OnCloseNoSave();
+}
+
+void CVcdBlockTool::OnCloseNoSave()
+{
+ DestroyTools();
+
+ if ( m_pDoc )
+ {
+ CAppNotifyScopeGuard sg( "CVcdBlockTool::OnCloseNoSave", NOTIFY_CHANGE_OTHER );
+
+ delete m_pDoc;
+ m_pDoc = NULL;
+
+ if ( m_hProperties )
+ {
+ m_hProperties->SetObject( NULL );
+ }
+ }
+
+ UpdateMenuBar( );
+}
+
+void CVcdBlockTool::OnMarkNotDirty()
+{
+ if ( m_pDoc )
+ {
+ m_pDoc->SetDirty( false );
+ }
+}
+
+
+void CVcdBlockTool::OnCopyEditsToVMF()
+{
+ if ( m_pDoc )
+ {
+ m_pDoc->CopyEditsToVMF();
+ }
+}
+
+
+void CVcdBlockTool::OnRememberPosition()
+{
+ m_bRememberPlayerPosition = !m_bRememberPlayerPosition;
+}
+
+
+void CVcdBlockTool::AttachAllEngineEntities()
+{
+ if ( !clienttools || !m_pDoc )
+ return;
+
+ /*
+ NOTE: This doesn't work for infotargets because they are server-only entities
+ for ( EntitySearchResult sr = clienttools->FirstEntity(); sr != NULL; sr = clienttools->NextEntity( sr ) )
+ {
+ if ( !sr )
+ continue;
+
+ HTOOLHANDLE handle = clienttools->AttachToEntity( sr );
+
+ const char *pClassName = clienttools->GetClassname( handle );
+ if ( Q_strcmp( pClassName, "class C_InfoTarget" ) == 0 )
+ {
+ Vector vecOrigin = clienttools->GetAbsOrigin( handle );
+ QAngle angAngles = clienttools->GetAbsAngles( handle );
+
+ // Find the associated commentary node entry in our doc
+ CDmeVMFEntity *pNode = m_pDoc->GetInfoTargetForLocation( vecOrigin, angAngles );
+ if ( pNode )
+ {
+ pNode->AttachToEngineEntity( handle );
+ }
+ }
+ }
+ */
+}
+
+
+//-----------------------------------------------------------------------------
+// Open a specific file
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OpenSpecificFile( const char *pFileName )
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc )
+ {
+ // File is already open
+ if ( !Q_stricmp( m_pDoc->GetEditFileName(), pFileName ) )
+ return;
+
+ if ( m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetEditFileName();
+ }
+ }
+
+ OpenFile( pFileName, "bsp", pSaveFileName, "vle", nFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the save document query dialog
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OpenFileFromHistory( int slot )
+{
+ const char *pFileName = m_RecentFiles.GetFile( slot );
+ if ( !pFileName )
+ return;
+ OpenSpecificFile( pFileName );
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get notified when files are saved/loaded
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues )
+{
+ if ( bWroteFile )
+ {
+ OnMarkNotDirty();
+ }
+
+ if ( !pContextKeyValues )
+ return;
+
+ if ( state != FileOpenStateMachine::SUCCESSFUL )
+ return;
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnClose" ) )
+ {
+ OnCloseNoSave();
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnQuit" ) )
+ {
+ OnCloseNoSave();
+ vgui::ivgui()->PostMessage( GetVPanel(), new KeyValues( "OnExit" ), 0 );
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "RestartLevel" ) )
+ {
+ OnRestartLevel();
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the File browser dialog
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ char pStartingDir[ MAX_PATH ];
+
+ if ( !Q_stricmp( pFileFormat, "bsp" ) )
+ {
+ GetModSubdirectory( "maps", pStartingDir, sizeof(pStartingDir) );
+ pDialog->SetTitle( "Choose Valve BSP File", true );
+ pDialog->SetStartDirectoryContext( "vcdblock_bsp_session", pStartingDir );
+ pDialog->AddFilter( "*.bsp", "Valve BSP File (*.bsp)", true );
+ }
+ else
+ {
+ GetModContentSubdirectory( "maps", pStartingDir, sizeof(pStartingDir) );
+ pDialog->SetTitle( "Choose Valve VLE File", true );
+ pDialog->SetStartDirectoryContext( "vcdblock_vle_session", pStartingDir );
+ pDialog->AddFilter( "*.vle", "Valve VLE File (*.vle)", true );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Can we quit?
+//-----------------------------------------------------------------------------
+bool CVcdBlockTool::CanQuit()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ // Show Save changes Yes/No/Cancel and re-quit if hit yes/no
+ SaveFile( m_pDoc->GetEditFileName(), "vle", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnQuit" ) );
+ return false;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Various command handlers related to the Edit menu
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnUndo()
+{
+ CDisableUndoScopeGuard guard;
+ g_pDataModel->Undo();
+}
+
+void CVcdBlockTool::OnRedo()
+{
+ CDisableUndoScopeGuard guard;
+ g_pDataModel->Redo();
+}
+
+void CVcdBlockTool::OnDescribeUndo()
+{
+ CUtlVector< UndoInfo_t > list;
+ g_pDataModel->GetUndoInfo( list );
+
+ Msg( "%i operations in stack\n", list.Count() );
+
+ for ( int i = list.Count() - 1; i >= 0; --i )
+ {
+ UndoInfo_t& entry = list[ i ];
+ if ( entry.terminator )
+ {
+ Msg( "[ '%s' ] - %i operations\n", entry.undo, entry.numoperations );
+ }
+
+ Msg( " +%s\n", entry.desc );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// VcdBlock menu items
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnAddNewNodes()
+{
+ if ( !m_pDoc )
+ return;
+
+ EnterTargetDropMode();
+}
+
+
+//-----------------------------------------------------------------------------
+// Background
+//-----------------------------------------------------------------------------
+const char *CVcdBlockTool::GetLogoTextureName()
+{
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from IVcdBlockDocCallback
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ if ( GetInfoTargetBrowser() )
+ {
+ if (nNotifyFlags & NOTIFY_CHANGE_TOPOLOGICAL)
+ {
+ GetInfoTargetBrowser()->UpdateEntityList();
+ }
+ else if (nNotifyFlags & NOTIFY_CHANGE_ATTRIBUTE_VALUE)
+ {
+ GetInfoTargetBrowser()->Refresh();
+ }
+ }
+
+ UpdateMenuBar();
+
+ /*
+ if ( bRefreshUI && m_hProperties.Get() )
+ {
+ m_hProperties->Refresh();
+ }
+ */
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads up a new document
+//-----------------------------------------------------------------------------
+bool CVcdBlockTool::LoadDocument( const char *pDocName )
+{
+ Assert( !m_pDoc );
+
+ DestroyTools();
+
+ m_pDoc = new CVcdBlockDoc( this );
+ if ( !m_pDoc->LoadFromFile( pDocName ) )
+ {
+ delete m_pDoc;
+ m_pDoc = NULL;
+ Warning( "Fatal error loading '%s'\n", pDocName );
+ return false;
+ }
+
+ ShowMiniViewport( true );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// The engine entities now exist, find them.
+//-----------------------------------------------------------------------------
+
+void CVcdBlockTool::ServerLevelInitPostEntity()
+{
+ if (!m_pDoc)
+ return;
+
+ m_pDoc->ServerLevelInitPostEntity();
+
+ CreateTools( m_pDoc );
+ InitTools();
+
+ if (m_bRememberPlayerPosition && m_bHasPlayerPosition)
+ {
+ m_bHasPlayerPosition = false;
+ servertools->SnapPlayerToPosition( m_vecPlayerOrigin, m_vecPlayerAngles );
+ }
+
+}
diff --git a/tools/vcdblock/vcdblocktool.h b/tools/vcdblock/vcdblocktool.h
new file mode 100644
index 0000000..f3a38d2
--- /dev/null
+++ b/tools/vcdblock/vcdblocktool.h
@@ -0,0 +1,239 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: VcdBlock tool; main UI smarts class
+//
+//=============================================================================
+
+#ifndef VCDBLOCKTOOL_H
+#define VCDBLOCKTOOL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/platform.h"
+#include "toolutils/basetoolsystem.h"
+#include "toolutils/recentfilelist.h"
+#include "toolutils/toolmenubar.h"
+#include "toolutils/toolswitchmenubutton.h"
+#include "toolutils/tooleditmenubutton.h"
+#include "toolutils/toolfilemenubutton.h"
+#include "toolutils/toolmenubutton.h"
+#include "datamodel/dmelement.h"
+#include "dmevmfentity.h"
+#include "toolframework/ienginetool.h"
+#include "toolutils/enginetools_int.h"
+#include "toolutils/savewindowpositions.h"
+#include "toolutils/toolwindowfactory.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CDmElement;
+class CVcdBlockDoc;
+class CInfoTargetPropertiesPanel;
+class CInfoTargetBrowserPanel;
+
+namespace vgui
+{
+ class Panel;
+}
+
+
+//-----------------------------------------------------------------------------
+// Allows the doc to call back into the VcdBlock editor tool
+//-----------------------------------------------------------------------------
+abstract_class IVcdBlockDocCallback
+{
+public:
+ // Called by the doc when the data changes
+ virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags ) = 0;
+};
+
+
+//-----------------------------------------------------------------------------
+// Global methods of the VCD Blocking tool
+//-----------------------------------------------------------------------------
+abstract_class IVcdBlockTool
+{
+public:
+ // Gets at the rool panel (for modal dialogs)
+ virtual vgui::Panel *GetRootPanel() = 0;
+
+ // Gets the registry name (for saving settings)
+ virtual const char *GetRegistryName() = 0;
+
+ // Shows a particular entity in the entity properties dialog
+ virtual void ShowEntityInEntityProperties( CDmeVMFEntity *pEntity ) = 0;
+};
+
+//-----------------------------------------------------------------------------
+// Implementation of the VcdBlock tool
+//-----------------------------------------------------------------------------
+class CVcdBlockTool : public CBaseToolSystem, public IFileMenuCallbacks, public IVcdBlockDocCallback, public IVcdBlockTool
+{
+ DECLARE_CLASS_SIMPLE( CVcdBlockTool, CBaseToolSystem );
+
+public:
+ CVcdBlockTool();
+
+ // Inherited from IToolSystem
+ virtual const char *GetToolName() { return "VCD Blocking Tool"; }
+ virtual bool Init( );
+ virtual void Shutdown();
+ virtual bool CanQuit();
+ virtual void OnToolActivate();
+ virtual void OnToolDeactivate();
+ virtual void ServerLevelInitPostEntity();
+ virtual void DrawEntitiesInEngine( bool bDrawInEngine );
+ virtual void ClientLevelInitPostEntity();
+ virtual void ClientLevelShutdownPreEntity();
+ virtual bool TrapKey( ButtonCode_t key, bool down );
+ virtual void ClientPreRender();
+
+ // Inherited from IFileMenuCallbacks
+ virtual int GetFileMenuItemsEnabled( );
+ virtual void AddRecentFilesToMenu( vgui::Menu *menu );
+ virtual bool GetPerforceFileName( char *pFileName, int nMaxLen );
+
+ // Inherited from IVcdBlockDocCallback
+ virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+ virtual vgui::Panel *GetRootPanel() { return this; }
+ virtual void ShowEntityInEntityProperties( CDmeVMFEntity *pEntity );
+
+ // Inherited from CBaseToolSystem
+ virtual vgui::HScheme GetToolScheme();
+ virtual vgui::Menu *CreateActionMenu( vgui::Panel *pParent );
+ virtual void OnCommand( const char *cmd );
+ virtual const char *GetRegistryName() { return "VcdBlockTool"; }
+ virtual const char *GetBindingsContextFile() { return "cfg/VcdBlock.kb"; }
+ virtual vgui::MenuBar *CreateMenuBar( CBaseToolSystem *pParent );
+
+ MESSAGE_FUNC( Save, "OnSave" );
+ void SaveAndTest();
+ void RestartMap();
+
+ // Enter mode where we preview dropping nodes
+ void EnterTargetDropMode();
+ void LeaveTargetDropMode();
+
+ bool IsMiniViewportCursor( int x, int y, Vector &org, Vector &forward );
+
+ // Save/Load game state
+ void SetRememberPlayerPosition( bool state = true ) { m_bRememberPlayerPosition = state; };
+ bool GetRememberPlayerPosition( void ) { return m_bRememberPlayerPosition; };
+ void QuickLoad();
+ void QuickSave();
+
+ bool IsInNodeDrag( void ) { return m_bInNodeDragMode; };
+
+public:
+ MESSAGE_FUNC( OnRestartLevel, "RestartLevel" );
+ MESSAGE_FUNC( OnNew, "OnNew" );
+ MESSAGE_FUNC( OnOpen, "OnOpen" );
+ MESSAGE_FUNC( OnSaveAs, "OnSaveAs" );
+ MESSAGE_FUNC( OnClose, "OnClose" );
+ MESSAGE_FUNC( OnCloseNoSave, "OnCloseNoSave" );
+ MESSAGE_FUNC( OnMarkNotDirty, "OnMarkNotDirty" );
+ MESSAGE_FUNC( OnExit, "OnExit" );
+
+ // Commands related to the edit menu
+ void OnDescribeUndo();
+
+ // Methods related to the VcdBlock menu
+ MESSAGE_FUNC( OnAddNewNodes, "AddNewNodes" );
+ MESSAGE_FUNC( OnCopyEditsToVMF, "CopyEditsToVMF" );
+ MESSAGE_FUNC( OnRememberPosition, "RememberPosition" );
+
+ // Methods related to the view menu
+ MESSAGE_FUNC( OnToggleProperties, "OnToggleProperties" );
+ MESSAGE_FUNC( OnToggleEntityReport, "OnToggleEntityReport" );
+ MESSAGE_FUNC( OnDefaultLayout, "OnDefaultLayout" );
+
+ // Keybindings
+ KEYBINDING_FUNC( undo, KEY_Z, vgui::MODIFIER_CONTROL, OnUndo, "#undo_help", 0 );
+ KEYBINDING_FUNC( redo, KEY_Z, vgui::MODIFIER_CONTROL | vgui::MODIFIER_SHIFT, OnRedo, "#redo_help", 0 );
+ KEYBINDING_FUNC_NODECLARE( VcdBlockAddNewNodes, KEY_A, vgui::MODIFIER_CONTROL, OnAddNewNodes, "#VcdBlockAddNewNodesHelp", 0 );
+
+ void OpenFileFromHistory( int slot );
+ void OpenSpecificFile( const char *pFileName );
+ virtual void SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual void OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues );
+
+ void AttachAllEngineEntities();
+
+ // returns the document
+ CVcdBlockDoc *GetDocument();
+
+ // Gets at tool windows
+ CInfoTargetPropertiesPanel *GetProperties();
+ CInfoTargetBrowserPanel *GetInfoTargetBrowser();
+
+ CDmeHandle< CDmeVMFEntity > GetCurrentEntity( void ) { return m_hCurrentEntity; }
+
+private:
+ // Loads up a new document
+ bool LoadDocument( const char *pDocName );
+
+ // Updates the menu bar based on the current file
+ void UpdateMenuBar( );
+
+ // Shows element properties
+ void ShowElementProperties( );
+
+ virtual const char *GetLogoTextureName();
+
+ // Creates, destroys tools
+ void CreateTools( CVcdBlockDoc *doc );
+ void DestroyTools();
+
+ // Initializes the tools
+ void InitTools();
+
+ // Shows, toggles tool windows
+ void ToggleToolWindow( Panel *tool, char const *toolName );
+ void ShowToolWindow( Panel *tool, char const *toolName, bool visible );
+
+ // Kills all tool windows
+ void DestroyToolContainers();
+
+ // Gets the position of the preview object
+ void GetPlacementInfo( Vector &vecOrigin, QAngle &angles );
+
+private:
+ // Document
+ CVcdBlockDoc *m_pDoc;
+
+ // The menu bar
+ CToolFileMenuBar *m_pMenuBar;
+
+ // Element properties for editing material
+ vgui::DHANDLE< CInfoTargetPropertiesPanel > m_hProperties;
+
+ // The entity report
+ vgui::DHANDLE< CInfoTargetBrowserPanel > m_hInfoTargetBrowser;
+
+ // The currently viewed entity
+ CDmeHandle< CDmeVMFEntity > m_hCurrentEntity;
+
+ // Separate undo context for the act busy tool
+ bool m_bInNodeDropMode;
+ bool m_bInNodeDragMode;
+ int m_iDragX;
+ int m_iDragY;
+ CDmeHandle< CDmeVMFEntity > m_hPreviewTarget;
+ CToolWindowFactory< ToolWindow > m_ToolWindowFactory;
+
+ // remembered player position
+ bool m_bRememberPlayerPosition;
+ bool m_bHasPlayerPosition;
+ Vector m_vecPlayerOrigin;
+ QAngle m_vecPlayerAngles;
+};
+
+extern CVcdBlockTool *g_pVcdBlockTool;
+
+#endif // VCDBLOCKTOOL_H
diff --git a/tools/vmt/vmt.vpc b/tools/vmt/vmt.vpc
new file mode 100644
index 0000000..920503e
--- /dev/null
+++ b/tools/vmt/vmt.vpc
@@ -0,0 +1,59 @@
+//-----------------------------------------------------------------------------
+// VMT.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin\tools"
+
+$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE,../common"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "$BASE Psapi.lib"
+ }
+}
+
+$Project "Vmt"
+{
+ $Folder "Source Files"
+ {
+ $File "$SRCDIR\public\interpolatortypes.cpp"
+ $File "$SRCDIR\public\movieobjects\movieobjects.cpp"
+ $File "$SRCDIR\public\registry.cpp"
+ $File "$SRCDIR\public\vgui_controls\vgui_controls.cpp"
+ $File "vmtdoc.cpp"
+ $File "vmttool.cpp"
+ }
+
+ $Folder "Header Files"
+ {
+ $File "$SRCDIR\public\interpolatortypes.h"
+ $File "vmtdoc.h"
+ $File "vmttool.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib datamodel
+ $Lib dmxloader
+ $Lib dme_controls
+ $Lib dmserializers
+ $Lib mathlib
+ $Lib matsys_controls
+ $Lib movieobjects
+ $Lib sfmobjects
+ $Lib tier2
+ $Lib tier3
+ $Lib toolutils
+ $Lib vgui_controls
+ }
+}
diff --git a/tools/vmt/vmtdoc.cpp b/tools/vmt/vmtdoc.cpp
new file mode 100644
index 0000000..665d932
--- /dev/null
+++ b/tools/vmt/vmtdoc.cpp
@@ -0,0 +1,1078 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "vmtdoc.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "datamodel/dmelement.h"
+#include "vmttool.h"
+#include "materialsystem/imaterialsystem.h"
+#include "materialsystem/ishader.h"
+#include "toolutils/enginetools_int.h"
+#include "filesystem.h"
+
+
+//-----------------------------------------------------------------------------
+// Standard properties
+//-----------------------------------------------------------------------------
+struct StandardParam_t
+{
+ const char *m_pParamName;
+ ShaderParamType_t m_ParamType;
+ const char *m_pDefaultValue;
+ const char *m_pWidgetType;
+ const char *m_pTextType;
+};
+
+// NOTE: All entries in here must have all-lowercase param names!
+static StandardParam_t g_pStandardParams[] =
+{
+ { "$surfaceprop", SHADER_PARAM_TYPE_STRING, "default", "surfacepropertypicker", "surfacePropertyName" },
+ { "%detailtype", SHADER_PARAM_TYPE_STRING, "", "detailtypepicker", "detailTypeName" },
+ { "%compilesky", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compilehint", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compileskip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compileorigin", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compileclip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%playerclip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compilenpcclip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compilenochop", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compiletrigger", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compilenolight", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compileplayercontrolclip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compileladder", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compilewet", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compilenodraw", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compileinvisible", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compilenonsolid", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compiledetail", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compilewater", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compileslime", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { NULL, SHADER_PARAM_TYPE_BOOL, NULL, NULL, NULL }
+};
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CVMTDoc::CVMTDoc( IVMTDocCallback *pCallback ) : m_pCallback( pCallback )
+{
+ m_hRoot = NULL;
+ m_pFileName[0] = 0;
+ m_bDirty = false;
+ m_pCurrentIShader = NULL;
+
+ KeyValues *pKeyValues = new KeyValues( "Wireframe" );
+ m_pScratchMaterial.Init( "VMT Preview", pKeyValues );
+ g_pDataModel->InstallNotificationCallback( this );
+}
+
+CVMTDoc::~CVMTDoc()
+{
+ if ( m_hRoot.Get() )
+ {
+ RemoveAllShaderParams( m_hRoot );
+ }
+ g_pDataModel->RemoveNotificationCallback( this );
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from INotifyUI
+//-----------------------------------------------------------------------------
+void CVMTDoc::NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ OnDataChanged( pReason, nNotifySource, nNotifyFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the file name
+//-----------------------------------------------------------------------------
+const char *CVMTDoc::GetFileName()
+{
+ return m_pFileName;
+}
+
+void CVMTDoc::SetFileName( const char *pFileName )
+{
+ Q_strncpy( m_pFileName, pFileName, sizeof( m_pFileName ) );
+ Q_FixSlashes( m_pFileName );
+ SetDirty( true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Dirty bits
+//-----------------------------------------------------------------------------
+void CVMTDoc::SetDirty( bool bDirty )
+{
+ m_bDirty = bDirty;
+}
+
+bool CVMTDoc::IsDirty() const
+{
+ return m_bDirty;
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates the root element
+//-----------------------------------------------------------------------------
+bool CVMTDoc::CreateRootElement()
+{
+ Assert( !m_hRoot.Get() );
+
+ DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( GetFileName() );
+
+ // Create the main element
+ m_hRoot = g_pDataModel->CreateElement( "DmElement", GetFileName(), fileid );
+ if ( m_hRoot == DMELEMENT_HANDLE_INVALID )
+ return false;
+
+ g_pDataModel->SetFileRoot( fileid, m_hRoot );
+
+ // Each VMT list needs to have an editortype associated with it so it displays nicely in editors
+ m_hRoot->SetValue( "editorType", "vmt" );
+ m_hRoot->AddAttribute( "proxies", AT_ELEMENT_ARRAY );
+ m_hRoot->AddAttribute( "fallbacks", AT_ELEMENT_ARRAY );
+
+ m_pCallback->RemoveAllToolParameters();
+
+ // Add standard parameters
+ for ( int i = 0; g_pStandardParams[i].m_pParamName; ++i )
+ {
+ AddNewShaderParam( m_hRoot, g_pStandardParams[i].m_pParamName, g_pStandardParams[i].m_ParamType,
+ g_pStandardParams[i].m_pDefaultValue );
+
+ if ( g_pStandardParams[i].m_pParamName[0] == '%' )
+ {
+ m_pCallback->AddToolParameter( g_pStandardParams[i].m_pParamName, g_pStandardParams[i].m_pWidgetType, g_pStandardParams[i].m_pTextType );
+ }
+ else if ( g_pStandardParams[i].m_pWidgetType || g_pStandardParams[i].m_pTextType )
+ {
+ m_pCallback->RemoveShaderParameter( g_pStandardParams[i].m_pParamName );
+ m_pCallback->AddShaderParameter( g_pStandardParams[i].m_pParamName, g_pStandardParams[i].m_pWidgetType, g_pStandardParams[i].m_pTextType );
+ }
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates a new VMT
+//-----------------------------------------------------------------------------
+void CVMTDoc::CreateNew()
+{
+ Assert( !m_hRoot.Get() );
+
+ // This is not undoable
+ CAppDisableUndoScopeGuard guard( "CVMTDoc::CreateNew", NOTIFY_CHANGE_OTHER );
+
+ Q_strncpy( m_pFileName, "untitled", sizeof( m_pFileName ) );
+
+ // Create the main element
+ if ( !CreateRootElement() )
+ return;
+
+ m_pPreviewMaterial.Init( m_pScratchMaterial );
+
+ SetShader( "wireframe" );
+ SetDirty( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Copies VMT parameters into the root
+//-----------------------------------------------------------------------------
+void CVMTDoc::CopyParamsFromVMT( CDmElement *pVMT )
+{
+ // First, set the shader parameters
+ SetShader( pVMT->GetValueString( "shader" ) );
+
+ // Now, copy the shader parameters over
+ CDmAttribute* pSrc;
+ CDmAttribute* pDst;
+ for ( pSrc = pVMT->FirstAttribute(); pSrc; pSrc = pSrc->NextAttribute() )
+ {
+ // Only copy shader parameters
+ if ( !IsShaderParam( pSrc ) )
+ continue;
+
+ // Adds the attribute if it doesn't exist
+ const char *pSrcName = pSrc->GetName();
+ if ( !m_hRoot->HasAttribute( pSrcName ) )
+ {
+ m_hRoot->AddAttribute( pSrcName, pSrc->GetType() );
+ }
+ pDst = m_hRoot->GetAttribute( pSrcName );
+ pDst->AddFlag( FATTRIB_USERDEFINED );
+
+ DmAttributeType_t srcType = pSrc->GetType();
+ DmAttributeType_t dstType = pDst->GetType();
+ if ( dstType == srcType )
+ {
+ pDst->SetValue( pSrc );
+ continue;
+ }
+
+ // Certain type conversions are allowed
+ switch( dstType )
+ {
+ case AT_BOOL:
+ if ( srcType == AT_INT )
+ {
+ pDst->SetValue( pSrc );
+ }
+ break;
+
+ case AT_INT:
+ if ( srcType == AT_BOOL )
+ {
+ pDst->SetValue( pSrc );
+ }
+ break;
+
+ case AT_COLOR:
+ if ( srcType == AT_VECTOR3 )
+ {
+ Color c;
+ int r, g, b;
+ Vector v = pSrc->GetValue<Vector>( );
+ v *= 255.0f;
+ r = clamp( v[0], 0, 255 );
+ g = clamp( v[1], 0, 255 );
+ b = clamp( v[2], 0, 255 );
+ c.SetColor( r, g, b, 255 );
+ pDst->SetValue( c );
+ }
+ break;
+ }
+ }
+
+ // Any shader parameter that isn't in the VMT make undefined
+ for ( pDst = m_hRoot->FirstAttribute(); pDst; pDst = pDst->NextAttribute() )
+ {
+ if ( !IsShaderParam( pDst ) )
+ continue;
+
+ if ( !pVMT->HasAttribute( pDst->GetName() ) )
+ {
+ // Special hack for alpha + colors
+ if ( !Q_stricmp( pDst->GetName(), "$alpha" ) )
+ {
+ pDst->SetValue( 1.0f );
+ }
+ else if ( pDst->GetType() == AT_COLOR )
+ {
+ Color c( 255, 255, 255, 255 );
+ pDst->SetValue( c );
+ }
+ else
+ {
+ pDst->SetToDefaultValue();
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Hooks the preview to an existing material, if there is one
+//-----------------------------------------------------------------------------
+void CVMTDoc::SetupPreviewMaterial( )
+{
+ // Extract a material name from the material
+ char pLocalName[MAX_PATH];
+
+ // relative paths can be passed in for in-game material picking
+ if ( !g_pFileSystem->FullPathToRelativePath( m_pFileName, pLocalName, sizeof(pLocalName) ) )
+ {
+ Q_strcpy( pLocalName, m_pFileName );
+ }
+
+ if ( Q_strnicmp( pLocalName, "materials", 9 ) )
+ goto noMaterialConnection;
+
+ // Skip the '/' also
+ char pMaterialName[MAX_PATH];
+ Q_StripExtension( pLocalName + 10, pMaterialName, sizeof(pMaterialName) );
+ IMaterial *pMaterial = g_pMaterialSystem->FindMaterial( pMaterialName, "Editable material", false );
+ if ( !pMaterial || pMaterial->IsErrorMaterial() )
+ goto noMaterialConnection;
+
+ m_pPreviewMaterial.Init( pMaterial );
+ return;
+
+noMaterialConnection:
+ m_pPreviewMaterial.Init( m_pScratchMaterial );
+}
+
+
+//-----------------------------------------------------------------------------
+// Saves/loads from file
+//-----------------------------------------------------------------------------
+bool CVMTDoc::LoadFromFile( const char *pFileName )
+{
+ Assert( !m_hRoot.Get() );
+
+ SetDirty( false );
+
+ Q_strncpy( m_pFileName, pFileName, sizeof( m_pFileName ) );
+ if ( !m_pFileName[0] )
+ return false;
+
+ // This is not undoable
+ CAppDisableUndoScopeGuard guard( "CVMTDoc::LoadFromFile", NOTIFY_CHANGE_OTHER );
+
+ // Create the main element
+ if ( !CreateRootElement() )
+ return false;
+
+ // change the filename of all the elements under the root, so we can unload the imported elements later
+ DmFileId_t rootFileId = g_pDataModel->GetFileId( m_pFileName );
+ g_pDataModel->SetFileName( rootFileId, "<temp>" );
+
+ // This will allow us to edit in context!
+ SetupPreviewMaterial( );
+
+ CDmElement *pIVMT = NULL;
+ g_pDataModel->RestoreFromFile( m_pFileName, NULL, "vmt", &pIVMT );
+ CDmElement *pVMT = CastElement< CDmElement >( pIVMT );
+ if ( !pVMT )
+ return false;
+
+ // FIXME: This is necessary so that all shader parameters appear in
+ // the same order, with the same type, as what you'd get using File->New.
+ // If we added a dependency to the material system into dmserializers,
+ // we could avoid this work here (I think!).
+ CopyParamsFromVMT( pVMT );
+
+ // unload the imported elements and change the root's filename back
+ DmFileId_t vmtFileId = g_pDataModel->GetFileId( m_pFileName );
+ g_pDataModel->RemoveFileId( vmtFileId );
+ g_pDataModel->SetFileName( rootFileId, m_pFileName );
+
+ SetDirty( false );
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Prior to saving to disk, extract all shader parameters which == the default
+//-----------------------------------------------------------------------------
+CDmElement* CVMTDoc::ExtractDefaultParameters( )
+{
+ CDmElement *pMaterial = m_hRoot->Copy( );
+
+ CDmAttribute* pAttribute = pMaterial->FirstAttribute();
+ CDmAttribute* pNextAttribute = NULL;
+ for ( ; pAttribute; pAttribute = pNextAttribute )
+ {
+ pNextAttribute = pAttribute->NextAttribute();
+
+ const char *pShaderParam = pAttribute->GetName();
+
+ // Check for standard params
+ int i;
+ for ( i = 0; g_pStandardParams[i].m_pParamName != NULL; ++i )
+ {
+ if ( !Q_stricmp( g_pStandardParams[i].m_pParamName, pShaderParam ) )
+ {
+ char temp[512];
+ CUtlBuffer buf( temp, sizeof(temp), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
+ pAttribute->Serialize( buf );
+
+ if ( !Q_stricmp( (char*)buf.Base(), g_pStandardParams[i].m_pDefaultValue ) )
+ {
+ // Buffers match! Therefore it's still using the default parameter
+ pMaterial->RemoveAttributeByPtr( pAttribute );
+ }
+ break;
+ }
+ }
+
+ // Standard attribute found, continue
+ if ( g_pStandardParams[i].m_pParamName )
+ continue;
+
+ // Only remove shader parameters
+ if ( !IsShaderParam( pAttribute ) )
+ continue;
+
+ // Remove flags whose value is 0
+ int nCount = g_pMaterialSystem->ShaderFlagCount();
+ for ( i = 0; i < nCount; ++i )
+ {
+ const char *pFlagName = g_pMaterialSystem->ShaderFlagName( i );
+ if ( !Q_stricmp( pShaderParam, pFlagName ) )
+ break;
+ }
+
+ // It's a flag! Remove the attribute if its value is 0
+ if ( i != nCount )
+ {
+ if ( pAttribute->GetValue<bool>( ) == 0 )
+ {
+ pMaterial->RemoveAttributeByPtr( pAttribute );
+ }
+ continue;
+ }
+
+ // FIXME: We can't do this.. the defaults in the strings need to be changed to
+ // make it so they actually match the true defaults
+ continue;
+
+ // Remove parameters which match the default value
+ nCount = m_pCurrentIShader->GetNumParams();
+ for ( i = 0; i < nCount; ++i )
+ {
+ // FIXME: Check type matches
+ if ( Q_stricmp( pShaderParam, m_pCurrentIShader->GetParamName( i ) ) )
+ continue;
+
+ // NOTE: This isn't particularly efficient. Too bad!
+ // It's hard to do efficiently owing to all the import conversion
+ char temp[512];
+ char temp2[512];
+ CUtlBuffer buf( temp, sizeof(temp), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
+ CUtlBuffer buf2( temp2, sizeof(temp2), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
+ pAttribute->Serialize( buf );
+ SetAttributeValueFromDefault( pMaterial, pAttribute, m_pCurrentIShader->GetParamDefault( i ) );
+ pAttribute->Serialize( buf2 );
+
+ if ( ( buf.TellMaxPut() == buf2.TellMaxPut() ) && !memcmp( buf.Base(), buf2.Base(), buf.TellMaxPut() ) )
+ {
+ // Buffers match! Therefore it's still using the default parameter
+ pMaterial->RemoveAttributeByPtr( pAttribute );
+ }
+ else
+ {
+ // Restore the actual value
+ pAttribute->Unserialize( buf );
+ }
+ break;
+ }
+ }
+
+ return pMaterial;
+}
+
+
+//-----------------------------------------------------------------------------
+// Saves to disk
+//-----------------------------------------------------------------------------
+bool CVMTDoc::SaveToFile( )
+{
+ if ( m_hRoot.Get() && m_pFileName && m_pFileName[0] )
+ {
+ CDisableUndoScopeGuard guard;
+ CDmElement *pSaveRoot = ExtractDefaultParameters();
+ bool bOk = g_pDataModel->SaveToFile( m_pFileName, NULL, "keyvalues", "vmt", pSaveRoot );
+ DestroyElement( pSaveRoot, TD_DEEP );
+ if ( !bOk )
+ return false;
+ }
+
+ SetDirty( false );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Finds a shader
+//-----------------------------------------------------------------------------
+IShader *CVMTDoc::FindShader( const char *pShaderName )
+{
+ int nCount = g_pMaterialSystem->ShaderCount();
+ IShader **ppShaderList = (IShader**)_alloca( nCount * sizeof(IShader*) );
+ g_pMaterialSystem->GetShaders( 0, nCount, ppShaderList );
+ for ( int i = 0; i < nCount; ++i )
+ {
+ if ( !Q_stricmp( pShaderName, ppShaderList[i]->GetName() ) )
+ return ppShaderList[i];
+ }
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Is this attribute a shader parameter?
+//-----------------------------------------------------------------------------
+bool CVMTDoc::IsShaderParam( CDmAttribute* pAttribute )
+{
+ const char *pName = pAttribute->GetName();
+
+ // Shader params start with a $ or %
+ if ( pName[0] != '$' && pName[0] != '%' )
+ return false;
+
+ // Don't remove name, type, or id
+ if ( pAttribute->IsFlagSet( FATTRIB_STANDARD ) )
+ return false;
+
+ // All shader params have USERDEFINED set
+ if ( !pAttribute->IsFlagSet( FATTRIB_USERDEFINED ) )
+ return false;
+
+ // Don't remove arrays... those aren't shader parameters
+ if ( pAttribute->GetType() == AT_ELEMENT_ARRAY )
+ return false;
+
+ // Standard params aren't counted here
+ for ( int i = 0; g_pStandardParams[i].m_pParamName; ++i )
+ {
+ if ( !Q_stricmp( g_pStandardParams[i].m_pParamName, pName ) )
+ return false;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Remove all shader parameters
+//-----------------------------------------------------------------------------
+void CVMTDoc::RemoveAllShaderParams( CDmElement *pMaterial )
+{
+ CDmAttribute* pAttribute;
+ CDmAttribute* pNextAttribute = NULL;
+ for ( pAttribute = pMaterial->FirstAttribute(); pAttribute; pAttribute = pNextAttribute )
+ {
+ pNextAttribute = pAttribute->NextAttribute();
+
+ // Only remove shader parameters
+ if ( !IsShaderParam( pAttribute ) )
+ continue;
+
+ m_pCallback->RemoveShaderParameter( pAttribute->GetName() );
+ pMaterial->RemoveAttributeByPtr( pAttribute );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Remove all shader parameters that don't exist in the new shader
+//-----------------------------------------------------------------------------
+void CVMTDoc::RemoveUnusedShaderParams( CDmElement *pMaterial, IShader *pShader, IShader *pOldShader )
+{
+ CDmAttribute* pAttribute = pMaterial->FirstAttribute();
+ CDmAttribute* pNextAttribute = NULL;
+ for ( ; pAttribute; pAttribute = pNextAttribute )
+ {
+ pNextAttribute = pAttribute->NextAttribute();
+
+ // Only remove shader parameters
+ if ( !IsShaderParam( pAttribute ) )
+ continue;
+
+ // Don't remove flags
+ int nCount = g_pMaterialSystem->ShaderFlagCount();
+ int i;
+ for ( i = 0; i < nCount; ++i )
+ {
+ const char *pFlagName = g_pMaterialSystem->ShaderFlagName( i );
+ if ( !Q_stricmp( pAttribute->GetName(), pFlagName ) )
+ break;
+ }
+
+ if ( i != nCount )
+ continue;
+
+ const char *pShaderParam = pAttribute->GetName();
+
+ // Remove parameters we've currently got but which don't exist in the new shader
+ nCount = pShader->GetNumParams();
+ for ( i = 0; i < nCount; ++i )
+ {
+ // FIXME: Check type matches
+ if ( !Q_stricmp( pShaderParam, pShader->GetParamName( i ) ) )
+ break;
+ }
+
+ // No match? Remove it!
+ if ( i == nCount )
+ {
+ m_pCallback->RemoveShaderParameter( pAttribute->GetName() );
+ pMaterial->RemoveAttributeByPtr( pAttribute );
+ continue;
+ }
+
+ // Remove parameters from the old shader which match the default value
+ // This will make the default values update to the new shader's defaults
+ if ( pOldShader )
+ {
+ nCount = pOldShader->GetNumParams();
+ for ( i = 0; i < nCount; ++i )
+ {
+ // FIXME: Check type matches
+ if ( Q_stricmp( pShaderParam, pOldShader->GetParamName( i ) ) )
+ continue;
+
+ // NOTE: This isn't particularly efficient. Too bad!
+ // It's hard to do efficiently owing to all the import conversion
+ char temp1[512];
+ char temp2[512];
+ CUtlBuffer buf1( temp1, sizeof(temp1), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
+ CUtlBuffer buf2( temp2, sizeof(temp2), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
+ pAttribute->Serialize( buf1 );
+ SetAttributeValueFromDefault( pMaterial, pAttribute, pOldShader->GetParamDefault( i ) );
+ pAttribute->Serialize( buf2 );
+
+ if ( ( buf1.TellMaxPut() == buf2.TellMaxPut() ) && !memcmp( buf1.Base(), buf2.Base(), buf1.TellMaxPut() ) )
+ {
+ // Buffers match! Therefore it's still using the default parameter
+ m_pCallback->RemoveShaderParameter( pAttribute->GetName() );
+ pMaterial->RemoveAttributeByPtr( pAttribute );
+ }
+ else
+ {
+ pAttribute->Unserialize( buf1 );
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Add attribute for shader parameter
+//-----------------------------------------------------------------------------
+CDmAttribute* CVMTDoc::AddAttributeForShaderParameter( CDmElement *pMaterial, const char *pParamName, ShaderParamType_t paramType )
+{
+ CDmAttribute *pAttribute = NULL;
+ switch ( paramType )
+ {
+ case SHADER_PARAM_TYPE_INTEGER:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_INT );
+ break;
+
+ case SHADER_PARAM_TYPE_BOOL:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_BOOL );
+ break;
+
+ case SHADER_PARAM_TYPE_FLOAT:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_FLOAT );
+ break;
+
+ case SHADER_PARAM_TYPE_STRING:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_STRING );
+ break;
+
+ case SHADER_PARAM_TYPE_COLOR:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_COLOR );
+ break;
+
+ case SHADER_PARAM_TYPE_VEC2:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_VECTOR2 );
+ break;
+
+ case SHADER_PARAM_TYPE_VEC3:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_VECTOR3 );
+ break;
+
+ case SHADER_PARAM_TYPE_VEC4:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_VECTOR4 );
+ break;
+
+ case SHADER_PARAM_TYPE_FOURCC:
+ Assert( 0 );
+ break;
+
+ case SHADER_PARAM_TYPE_MATRIX:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_VMATRIX );
+ break;
+
+ case SHADER_PARAM_TYPE_TEXTURE:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_STRING );
+ m_pCallback->AddShaderParameter( pParamName, "vtfpicker", "vtfName" );
+ break;
+
+ case SHADER_PARAM_TYPE_MATERIAL:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_STRING );
+ m_pCallback->AddShaderParameter( pParamName, "vmtpicker", "vmtName" );
+ break;
+
+ default:
+ break;
+ }
+
+ if ( pAttribute )
+ {
+ pAttribute->AddFlag( FATTRIB_USERDEFINED );
+ }
+
+ return pAttribute;
+}
+
+
+//-----------------------------------------------------------------------------
+// A couple methods to set vmatrix param values from strings (OLD METHOD!)
+//-----------------------------------------------------------------------------
+bool CVMTDoc::SetVMatrixParamValue( CDmAttribute *pAttribute, const char *pValue )
+{
+ // FIXME: Change default strings to match DME?
+ // Then we could remove this crap
+ VMatrix mat;
+ int count = sscanf( pValue, " [ %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f ]",
+ &mat.m[0][0], &mat.m[0][1], &mat.m[0][2], &mat.m[0][3],
+ &mat.m[1][0], &mat.m[1][1], &mat.m[1][2], &mat.m[1][3],
+ &mat.m[2][0], &mat.m[2][1], &mat.m[2][2], &mat.m[2][3],
+ &mat.m[3][0], &mat.m[3][1], &mat.m[3][2], &mat.m[3][3] );
+ if (count == 16)
+ {
+ pAttribute->SetValue( mat );
+ return true;
+ }
+
+ Vector2D scale, center;
+ float angle;
+ Vector2D translation;
+ count = sscanf( pValue, " center %f %f scale %f %f rotate %f translate %f %f",
+ &center.x, &center.y, &scale.x, &scale.y, &angle, &translation.x, &translation.y );
+ if (count != 7)
+ return false;
+
+ VMatrix temp;
+ MatrixBuildTranslation( mat, -center.x, -center.y, 0.0f );
+ MatrixBuildScale( temp, scale.x, scale.y, 1.0f );
+ MatrixMultiply( temp, mat, mat );
+ MatrixBuildRotateZ( temp, angle );
+ MatrixMultiply( temp, mat, mat );
+ MatrixBuildTranslation( temp, center.x + translation.x, center.y + translation.y, 0.0f );
+ MatrixMultiply( temp, mat, mat );
+ pAttribute->SetValue( mat );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// A couple methods to set vmatrix param values from strings (OLD METHOD!)
+//-----------------------------------------------------------------------------
+bool CVMTDoc::SetVector2DParamValue( CDmAttribute *pAttribute, const char *pValue )
+{
+ Vector2D vec;
+ int count = sscanf( pValue, " [ %f %f ]", &vec[0], &vec[1] );
+ if ( count == 2 )
+ {
+ pAttribute->SetValue( vec );
+ return true;
+ }
+
+ count = sscanf( pValue, " { %f %f }", &vec[0], &vec[1] );
+ if ( count == 2 )
+ {
+ vec /= 255.0f;
+ pAttribute->SetValue( vec );
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// A couple methods to set vmatrix param values from strings (OLD METHOD!)
+//-----------------------------------------------------------------------------
+bool CVMTDoc::SetVector3DParamValue( CDmAttribute *pAttribute, const char *pValue )
+{
+ Vector vec;
+ int count = sscanf( pValue, " [ %f %f %f ]", &vec[0], &vec[1], &vec[2] );
+ if ( count == 3 )
+ {
+ pAttribute->SetValue( vec );
+ return true;
+ }
+
+ count = sscanf( pValue, " { %f %f %f }", &vec[0], &vec[1], &vec[2] );
+ if ( count == 3 )
+ {
+ vec /= 255.0f;
+ pAttribute->SetValue( vec );
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// A couple methods to set vmatrix param values from strings (OLD METHOD!)
+//-----------------------------------------------------------------------------
+bool CVMTDoc::SetVector4DParamValue( CDmAttribute *pAttribute, const char *pValue )
+{
+ Vector4D vec;
+ int count = sscanf( pValue, " [ %f %f %f %f ]", &vec[0], &vec[1], &vec[2], &vec[3] );
+ if ( count == 4 )
+ {
+ pAttribute->SetValue( vec );
+ return true;
+ }
+
+ count = sscanf( pValue, " { %f %f %f %f }", &vec[0], &vec[1], &vec[2], &vec[3] );
+ if ( count == 4 )
+ {
+ vec /= 255.0f;
+ pAttribute->SetValue( vec );
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// A couple methods to set vmatrix param values from strings (OLD METHOD!)
+//-----------------------------------------------------------------------------
+bool CVMTDoc::SetColorParamValue( CDmAttribute *pAttribute, const char *pValue )
+{
+ Color c;
+ int r, g, b;
+ Vector vec;
+ int count = sscanf( pValue, " [ %f %f %f ]", &vec[0], &vec[1], &vec[2] );
+ if ( count == 3 )
+ {
+ vec *= 255.0f;
+ r = clamp( vec[0], 0, 255 );
+ g = clamp( vec[1], 0, 255 );
+ b = clamp( vec[2], 0, 255 );
+ c.SetColor( r, g, b, 255 );
+ pAttribute->SetValue( c );
+ return true;
+ }
+
+ count = sscanf( pValue, " { %d %d %d }", &r, &g, &b );
+ if ( count == 3 )
+ {
+ c.SetColor( r, g, b, 255 );
+ pAttribute->SetValue( c );
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets an attribute value from the shader param default
+//-----------------------------------------------------------------------------
+void CVMTDoc::SetAttributeValueFromDefault( CDmElement *pMaterial, CDmAttribute *pAttribute, const char *pValue )
+{
+ // FIXME: Change default strings to match DME?
+ // Then we could remove this crap
+ switch ( pAttribute->GetType() )
+ {
+ case AT_VMATRIX:
+ if ( SetVMatrixParamValue( pAttribute, pValue ) )
+ return;
+ break;
+ case AT_COLOR:
+ if ( SetColorParamValue( pAttribute, pValue ) )
+ return;
+ break;
+ case AT_VECTOR2:
+ if ( SetVector2DParamValue( pAttribute, pValue ) )
+ return;
+ break;
+ case AT_VECTOR3:
+ if ( SetVector3DParamValue( pAttribute, pValue ) )
+ return;
+ break;
+ case AT_VECTOR4:
+ if ( SetVector4DParamValue( pAttribute, pValue ) )
+ return;
+ break;
+ }
+
+ pMaterial->SetValueFromString( pAttribute->GetName(), pValue );
+}
+
+
+//-----------------------------------------------------------------------------
+// Add a single shader parameter if it doesn't exist
+//-----------------------------------------------------------------------------
+void CVMTDoc::AddNewShaderParam( CDmElement *pMaterial, const char *pParamName, ShaderParamType_t paramType, const char *pValue )
+{
+ char temp[512];
+ Q_strncpy( temp, pParamName, sizeof(temp) );
+ Q_strlower( temp );
+ pParamName = temp;
+
+ CDmAttribute* pAttribute = NULL;
+ for ( pAttribute = pMaterial->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
+ {
+ // Don't bother testing against name, type, or id
+ if ( pAttribute->IsFlagSet( FATTRIB_STANDARD ) )
+ continue;
+
+ const char *pAttributeName = pAttribute->GetName();
+ if ( !Q_stricmp( pAttributeName, pParamName ) )
+ return;
+ }
+
+ // No match? Add it!
+ pAttribute = AddAttributeForShaderParameter( pMaterial, pParamName, paramType );
+ if ( pAttribute )
+ {
+ SetAttributeValueFromDefault( pMaterial, pAttribute, pValue );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Add all shader parameters that don't currently exist
+//-----------------------------------------------------------------------------
+void CVMTDoc::AddNewShaderParams( CDmElement *pMaterial, IShader *pShader )
+{
+ // First add all flags
+ m_pCallback->RemoveAllFlagParameters();
+ int nCount = g_pMaterialSystem->ShaderFlagCount();
+ int i;
+ for ( i = 0; i < nCount; ++i )
+ {
+ const char *pParamName = g_pMaterialSystem->ShaderFlagName( i );
+ AddNewShaderParam( pMaterial, pParamName, SHADER_PARAM_TYPE_BOOL, "0" );
+ m_pCallback->AddFlagParameter( pParamName );
+ }
+
+ // Next add all shader-specific parameters
+ nCount = pShader->GetNumParams();
+ for ( i = 0; i < nCount; ++i )
+ {
+ const char *pParamName = pShader->GetParamName( i );
+
+ // Don't add parameters that don't want to be editable
+ if ( pShader->GetParamFlags( i ) & SHADER_PARAM_NOT_EDITABLE )
+ continue;
+
+ ShaderParamType_t paramType = pShader->GetParamType( i );
+ const char *pDefault = pShader->GetParamDefault( i );
+ AddNewShaderParam( pMaterial, pParamName, paramType, pDefault );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets shader parameters to the default for that shader
+//-----------------------------------------------------------------------------
+void CVMTDoc::SetParamsToDefault()
+{
+ // This is undoable
+ CAppUndoScopeGuard guard( 0, "Set Params to Default", "Set Params to Default" );
+
+ // Next add all shader-specific parameters
+ int nCount = m_pCurrentIShader->GetNumParams();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ const char *pParamName = m_pCurrentIShader->GetParamName( i );
+
+ // Don't set parameters that don't want to be editable
+ if ( m_pCurrentIShader->GetParamFlags( i ) & SHADER_PARAM_NOT_EDITABLE )
+ continue;
+
+ char pAttributeName[512];
+ Q_strncpy( pAttributeName, pParamName, sizeof(pAttributeName) );
+ Q_strlower( pAttributeName );
+
+ if ( !m_hRoot->HasAttribute( pAttributeName ) )
+ continue;
+
+ CDmAttribute *pAttribute = m_hRoot->GetAttribute( pAttributeName );
+ const char *pDefault = m_pCurrentIShader->GetParamDefault( i );
+ SetAttributeValueFromDefault( m_hRoot, pAttribute, pDefault );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the shader in the material
+//-----------------------------------------------------------------------------
+void CVMTDoc::SetShader( const char *pShaderName )
+{
+ // No change? don't bother
+ if ( !Q_stricmp( m_CurrentShader, pShaderName ) )
+ return;
+
+ m_CurrentShader = pShaderName;
+
+ // This is undoable
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Set Shader", "Set Shader" );
+
+ char pActualShaderName[512];
+ g_pMaterialSystem->GetShaderFallback( pShaderName, pActualShaderName, sizeof(pActualShaderName) );
+
+ m_hRoot->SetValue( "shader", pShaderName );
+
+ // First, find the shader
+ IShader *pShader = FindShader( pActualShaderName );
+
+ // Remove all shader parameters that don't exist in the new shader
+ // And also remove shader parameters that do match the default value
+ RemoveUnusedShaderParams( m_hRoot, pShader, m_pCurrentIShader );
+
+ // Add all shader parameters that don't currently exist
+ AddNewShaderParams( m_hRoot, pShader );
+
+ m_pCurrentIShader = pShader;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the preview material
+//-----------------------------------------------------------------------------
+IMaterial *CVMTDoc::GetPreviewMaterial()
+{
+ return m_pPreviewMaterial;
+}
+
+
+//-----------------------------------------------------------------------------
+// Updates the preview material
+//-----------------------------------------------------------------------------
+void CVMTDoc::UpdatePreviewMaterial()
+{
+ if ( !m_hRoot.Get() )
+ return;
+
+ // Update all shader parameters
+ SetShader( m_hRoot->GetValueString( "shader" ) );
+
+ // Use the file conversion to write to a text format
+ char buf[1024];
+ CUtlBuffer vmtBuf( buf, sizeof(buf), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
+ g_pDataModel->Serialize( vmtBuf, "vmt", "vmt", m_hRoot );
+
+ // Now use the text format to create a keyvalues
+ KeyValues *pVMTKeyValues = new KeyValues( "ShaderName" );
+ pVMTKeyValues->LoadFromBuffer( "VMT Preview", vmtBuf, g_pFileSystem, "GAME" );
+
+ // Finally, hook the keyvalues into the material.
+ m_pPreviewMaterial->SetShaderAndParams( pVMTKeyValues );
+ pVMTKeyValues->deleteThis();
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the root object
+//-----------------------------------------------------------------------------
+CDmElement *CVMTDoc::GetRootObject()
+{
+ return m_hRoot;
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when data changes
+//-----------------------------------------------------------------------------
+void CVMTDoc::OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ SetDirty( nNotifyFlags & NOTIFY_SETDIRTYFLAG ? true : false );
+ UpdatePreviewMaterial();
+ m_pCallback->OnDocChanged( pReason, nNotifySource, nNotifyFlags );
+}
diff --git a/tools/vmt/vmtdoc.h b/tools/vmt/vmtdoc.h
new file mode 100644
index 0000000..8b9d876
--- /dev/null
+++ b/tools/vmt/vmtdoc.h
@@ -0,0 +1,133 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef VMTDOC_H
+#define VMTDOC_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "dme_controls/inotifyui.h"
+#include "datamodel/dmehandle.h"
+#include "materialsystem/MaterialSystemUtil.h"
+#include "tier1/utlstring.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class IVMTDocCallback;
+class IShader;
+enum ShaderParamType_t;
+class IMaterial;
+class IShader;
+
+
+//-----------------------------------------------------------------------------
+// Contains all editable state
+//-----------------------------------------------------------------------------
+class CVMTDoc : public IDmNotify
+{
+public:
+ CVMTDoc( IVMTDocCallback *pCallback );
+ ~CVMTDoc();
+
+ // Inherited from INotifyUI
+ virtual void NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Sets/Gets the file name
+ const char *GetFileName();
+ void SetFileName( const char *pFileName );
+
+ // Dirty bits (has it changed since the last time it was saved?)
+ void SetDirty( bool bDirty );
+ bool IsDirty() const;
+
+ // Creates a new act busy list
+ void CreateNew();
+
+ // Saves/loads from file
+ bool LoadFromFile( const char *pFileName );
+ bool SaveToFile( );
+
+ // Returns the root object
+ CDmElement *GetRootObject();
+
+ // Called when data changes (see INotifyUI for flags)
+ void OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Sets the shader in the material
+ void SetShader( const char *pShaderName );
+
+ // Gets the preview material
+ IMaterial *GetPreviewMaterial();
+
+ // Sets shader parameters to the default for that shader
+ void SetParamsToDefault();
+
+private:
+ // Creates the root element
+ bool CreateRootElement();
+
+ // Add attribute for shader parameter
+ CDmAttribute* AddAttributeForShaderParameter( CDmElement *pMaterial, const char *pParamName, ShaderParamType_t paramType );
+
+ // Add a single shader parameter if it doesn't exist
+ void AddNewShaderParam( CDmElement *pMaterial, const char *pParamName, ShaderParamType_t paramType, const char *pValue );
+
+ // Add all shader parameters that don't currently exist
+ void AddNewShaderParams( CDmElement *pMaterial, IShader *pShader );
+
+ // Is this attribute a shader parameter?
+ bool IsShaderParam( CDmAttribute* pAttribute );
+
+ // Remove all shader parameters that don't exist in the new shader
+ void RemoveUnusedShaderParams( CDmElement *pMaterial, IShader *pShader, IShader *pOldShader );
+
+ // Remove all shader parameters
+ void RemoveAllShaderParams( CDmElement *pMaterial );
+
+ // Finds a shader
+ IShader *FindShader( const char *pShaderName );
+
+ // Updates the preview material
+ void UpdatePreviewMaterial();
+
+ // Copies VMT parameters into the root
+ void CopyParamsFromVMT( CDmElement *pVMT );
+
+ // A couple methods to set param values from strings (OLD METHOD!)
+ bool SetVMatrixParamValue( CDmAttribute *pAttribute, const char *pValue );
+ bool SetVector2DParamValue( CDmAttribute *pAttribute, const char *pValue );
+ bool SetVector3DParamValue( CDmAttribute *pAttribute, const char *pValue );
+ bool SetVector4DParamValue( CDmAttribute *pAttribute, const char *pValue );
+ bool SetColorParamValue( CDmAttribute *pAttribute, const char *pValue );
+
+ // Sets an attribute value from the shader param default
+ void SetAttributeValueFromDefault( CDmElement *pMaterial, CDmAttribute *pAttribute, const char *pValue );
+
+ // Hooks the preview to an existing material, if there is one
+ void SetupPreviewMaterial( );
+
+ // Prior to saving to disk, extract all shader parameters which == the default
+ CDmElement* ExtractDefaultParameters( );
+
+ IVMTDocCallback *m_pCallback;
+ CMaterialReference m_pScratchMaterial;
+ CMaterialReference m_pPreviewMaterial;
+ CDmeHandle< CDmElement > m_hRoot;
+ CUtlString m_CurrentShader;
+ IShader *m_pCurrentIShader;
+ char m_pFileName[512];
+ bool m_bDirty;
+};
+
+
+#endif // VMTDOC_H
diff --git a/tools/vmt/vmttool.cpp b/tools/vmt/vmttool.cpp
new file mode 100644
index 0000000..a42f672
--- /dev/null
+++ b/tools/vmt/vmttool.cpp
@@ -0,0 +1,1337 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Act busy tool; main UI smarts class
+//
+//=============================================================================
+
+#include "toolutils/basetoolsystem.h"
+#include "toolutils/toolmenubar.h"
+#include "toolutils/toolswitchmenubutton.h"
+#include "toolutils/toolfilemenubutton.h"
+#include "toolutils/tooleditmenubutton.h"
+#include "toolutils/toolmenubutton.h"
+#include "vgui_controls/Menu.h"
+#include "tier1/KeyValues.h"
+#include "toolutils/enginetools_int.h"
+#include "toolframework/ienginetool.h"
+#include "vgui/IInput.h"
+#include "vgui/KeyCode.h"
+#include "vgui_controls/FileOpenDialog.h"
+#include "filesystem.h"
+#include "vmtdoc.h"
+#include "vgui/ilocalize.h"
+#include "dme_controls/elementpropertiestree.h"
+#include "matsys_controls/vmtpanel.h"
+#include "vmttool.h"
+#include "movieobjects/dmeeditortypedictionary.h"
+#include "dme_controls/attributestringchoicepanel.h"
+#include "matsys_controls/mdlsequencepicker.h"
+#include "istudiorender.h"
+#include "materialsystem/imaterialsystem.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "toolutils/toolwindowfactory.h"
+#include "toolutils/basepropertiescontainer.h"
+#include "toolutils/savewindowpositions.h"
+#include "tier3/tier3.h"
+#include "tier2/fileutils.h"
+#include "vgui/ivgui.h"
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Singleton interfaces
+//-----------------------------------------------------------------------------
+CDmeEditorTypeDictionary *g_pEditorTypeDict;
+
+
+//-----------------------------------------------------------------------------
+// Methods needed by scenedatabase. They have to live here instead of toolutils
+// because this is a DLL but toolutils is only a static library
+//-----------------------------------------------------------------------------
+char const *GetVGuiControlsModuleName()
+{
+ return "VMTTool";
+}
+
+//-----------------------------------------------------------------------------
+// Connect, disconnect
+//-----------------------------------------------------------------------------
+bool ConnectTools( CreateInterfaceFn factory )
+{
+ return (g_pMDLCache != NULL) && (studiorender != NULL) && (materials != NULL) && (g_pMatSystemSurface != NULL);
+}
+
+void DisconnectTools( )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Implementation of the act busy tool
+//-----------------------------------------------------------------------------
+class CVMTTool : public CBaseToolSystem, public IFileMenuCallbacks, public IVMTDocCallback
+{
+ DECLARE_CLASS_SIMPLE( CVMTTool, CBaseToolSystem );
+
+public:
+ CVMTTool();
+
+ // Inherited from IToolSystem
+ virtual char const *GetToolName() { return "Material Editor"; }
+ virtual const char *GetBindingsContextFile() { return "cfg/VMTTool.kb"; }
+ virtual bool Init();
+ virtual void Shutdown();
+ virtual bool CanQuit( );
+ virtual void PostMessage( HTOOLHANDLE hEntity, KeyValues *message );
+
+ // Inherited from IFileMenuCallbacks
+ virtual int GetFileMenuItemsEnabled( );
+ virtual void AddRecentFilesToMenu( vgui::Menu *menu );
+ virtual bool GetPerforceFileName( char *pFileName, int nMaxLen );
+ virtual vgui::Panel* GetRootPanel() { return this; }
+
+ // Inherited from IVMTDocCallback
+ virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+ virtual void AddShaderParameter( const char *pParam, const char *pWidget, const char *pTextType );
+ virtual void RemoveShaderParameter( const char *pParam );
+ virtual void AddFlagParameter( const char *pParam );
+ virtual void AddToolParameter( const char *pParam, const char *pWidget, const char *pTextType );
+ virtual void RemoveAllFlagParameters();
+ virtual void RemoveAllToolParameters();
+
+ // Inherited from CBaseToolSystem
+ virtual vgui::HScheme GetToolScheme();
+ virtual vgui::Menu *CreateActionMenu( vgui::Panel *pParent );
+ virtual void OnCommand( const char *cmd );
+ virtual const char *GetRegistryName() { return "VMT"; }
+ virtual vgui::MenuBar *CreateMenuBar( CBaseToolSystem *pParent );
+ virtual void OnToolActivate();
+ virtual void OnToolDeactivate();
+ virtual CVMTDoc *GetDocument();
+ virtual CBasePropertiesContainer *GetProperties();
+ virtual void SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual void OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues );
+
+public:
+ // Commands related to the file menu
+ MESSAGE_FUNC( OnNew, "OnNew" );
+ MESSAGE_FUNC( OnOpen, "OnOpen" );
+ MESSAGE_FUNC( OnSave, "OnSave" );
+ MESSAGE_FUNC( OnSaveAs, "OnSaveAs" );
+ MESSAGE_FUNC( OnClose, "OnClose" );
+ MESSAGE_FUNC( OnCloseNoSave, "OnCloseNoSave" );
+ MESSAGE_FUNC( OnMarkNotDirty, "OnMarkNotDirty" );
+ MESSAGE_FUNC( OnExit, "OnExit" );
+ void PerformNew();
+ void OpenFileFromHistory( int slot, const char *pCommand );
+ void OpenSpecificFile( const char *pFileName );
+
+ // Commands related to the edit menu
+ KEYBINDING_FUNC( undo, KEY_Z, vgui::MODIFIER_CONTROL, OnUndo, "#undo_help", 0 );
+ KEYBINDING_FUNC( redo, KEY_Z, vgui::MODIFIER_CONTROL | vgui::MODIFIER_SHIFT, OnRedo, "#redo_help", 0 );
+ void OnDescribeUndo();
+
+ // Methods related to the view menu
+ MESSAGE_FUNC( OnToggleProperties, "OnToggleProperties" );
+ MESSAGE_FUNC( OnToggleVMTPreview, "OnToggleVMTPreview" );
+ MESSAGE_FUNC( OnShowFlags, "OnShowFlags" );
+ MESSAGE_FUNC( OnShowToolParams, "OnShowToolParams" );
+ MESSAGE_FUNC( OnDefaultLayout, "OnDefaultLayout" );
+
+ // Methods related to the material menu
+ MESSAGE_FUNC( OnSetParamsToDefault, "OnSetParamsToDefault" );
+
+ // Returns the VMT preview window
+ CVMTPanel *GetVMTPreview();
+
+ // Which parameters are visible?
+ bool IsFlagParamsVisible() const;
+ bool IsToolParamsVisible() const;
+
+private:
+ // Flags for HideStandardFields
+ enum EditorTypeStandardFields_t
+ {
+ EDITOR_FIELD_NAME = 0x1,
+ EDITOR_FIELD_TYPE = 0x2,
+ EDITOR_FIELD_ID = 0x4,
+ EDITOR_FIELD_EDITORTYPE = 0x8,
+ };
+
+ void HideStandardFields( CDmeEditorType *pEditorType, int nFieldFlags );
+
+ // Creates a new document
+ void NewDocument( );
+
+ // Loads up a new document
+ bool LoadDocument( char const *pDocName );
+
+ // Updates the menu bar based on the current file
+ void UpdateMenuBar( );
+
+ // Shows element properties
+ void ShowElementProperties( );
+
+ // Create custom editors
+ void InitEditorDict();
+
+ void CreateTools( CVMTDoc *doc );
+ void InitTools();
+ void DestroyTools();
+
+ void ToggleToolWindow( Panel *tool, char const *toolName );
+ void ShowToolWindow( Panel *tool, char const *toolName, bool visible );
+
+ void DestroyToolContainers();
+
+ virtual char const *GetLogoTextureName();
+
+private:
+ // All editable data
+ CVMTDoc *m_pDoc;
+
+ // The menu bar
+ CToolFileMenuBar *m_pMenuBar;
+
+ // Element properties for editing material
+ vgui::DHANDLE< CBasePropertiesContainer > m_hProperties;
+
+ // The sequence picker!
+ vgui::DHANDLE< CVMTPanel > m_hVMTPreview;
+
+ // The VMT editor type
+ CDmeEditorType *m_pVMTType;
+
+ // Separate undo context for the act busy tool
+ CToolWindowFactory< ToolWindow > m_ToolWindowFactory;
+
+ // List of tool + flag parameters
+ CUtlVector<CUtlString> m_ToolParams;
+ CUtlVector<CUtlString> m_FlagParams;
+
+ bool m_bToolParamsVisible;
+ bool m_bFlagParamsVisible;
+
+ CUtlVector< DmElementHandle_t > m_toolElements;
+};
+
+
+//-----------------------------------------------------------------------------
+// Singleton
+//-----------------------------------------------------------------------------
+CVMTTool *g_pVMTTool = NULL;
+
+void CreateTools()
+{
+ g_pVMTTool = new CVMTTool();
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CVMTTool::CVMTTool()
+{
+ m_pVMTType = NULL;
+ m_pMenuBar = NULL;
+ m_pDoc = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Init, shutdown
+//-----------------------------------------------------------------------------
+bool CVMTTool::Init()
+{
+ m_bToolParamsVisible = false;
+ m_bFlagParamsVisible = true;
+ m_pDoc = NULL;
+ m_RecentFiles.LoadFromRegistry( GetRegistryName() );
+
+ // NOTE: This has to happen before BaseClass::Init
+ g_pVGuiLocalize->AddFile( "resource/toolvmt_%language%.txt" );
+
+ if ( !BaseClass::Init() )
+ return false;
+
+ InitEditorDict();
+
+ return true;
+}
+
+void CVMTTool::Shutdown()
+{
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+
+ {
+ CDisableUndoScopeGuard sg;
+ int nElements = m_toolElements.Count();
+ for ( int i = 0; i < nElements; ++i )
+ {
+ g_pDataModel->DestroyElement( m_toolElements[ i ] );
+ }
+ }
+
+ BaseClass::Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// Tool activation/deactivation
+//-----------------------------------------------------------------------------
+void CVMTTool::OnToolActivate()
+{
+ BaseClass::OnToolActivate();
+}
+
+void CVMTTool::OnToolDeactivate()
+{
+ BaseClass::OnToolDeactivate();
+}
+
+
+//-----------------------------------------------------------------------------
+// Hides standard fields
+//-----------------------------------------------------------------------------
+void CVMTTool::HideStandardFields( CDmeEditorType *pEditorType, int nFieldFlags )
+{
+ CDmeEditorAttributeInfo *pInfo;
+
+ if ( nFieldFlags & EDITOR_FIELD_NAME )
+ {
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "name info", pEditorType->GetFileId() );
+ pEditorType->AddAttributeInfo( "name", pInfo );
+ pInfo->m_bIsVisible = false;
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+ }
+
+ if ( nFieldFlags & EDITOR_FIELD_TYPE )
+ {
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "type info", pEditorType->GetFileId() );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "type", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+ }
+
+ if ( nFieldFlags & EDITOR_FIELD_ID )
+ {
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "id info", pEditorType->GetFileId() );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "id", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+ }
+
+ if ( nFieldFlags & EDITOR_FIELD_EDITORTYPE )
+ {
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "editor type info", pEditorType->GetFileId() );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "editorType", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Update the editor dict based on the current material parameters
+//-----------------------------------------------------------------------------
+void CVMTTool::AddShaderParameter( const char *pParam, const char *pWidget, const char *pTextType )
+{
+ // anims only accept activity names
+ CDmeEditorAttributeInfo *pInfo = CreateElement< CDmeEditorAttributeInfo >( "shader param info", m_pVMTType->GetFileId() );
+ m_pVMTType->AddAttributeInfo( pParam, pInfo );
+ pInfo->m_Widget = pWidget;
+ if ( pTextType )
+ {
+ pInfo->SetValue( "texttype", pTextType );
+ }
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Update the editor dict based on the current material parameters
+//-----------------------------------------------------------------------------
+void CVMTTool::RemoveShaderParameter( const char *pParam )
+{
+ m_pVMTType->RemoveAttributeInfo( pParam );
+}
+
+
+//-----------------------------------------------------------------------------
+// Which parameters are visible?
+//-----------------------------------------------------------------------------
+inline bool CVMTTool::IsFlagParamsVisible() const
+{
+ return m_bFlagParamsVisible;
+}
+
+inline bool CVMTTool::IsToolParamsVisible() const
+{
+ return m_bToolParamsVisible;
+}
+
+
+//-----------------------------------------------------------------------------
+// Adds flags, tool parameters
+//-----------------------------------------------------------------------------
+void CVMTTool::AddFlagParameter( const char *pParam )
+{
+ Assert( m_pVMTType->GetAttributeInfo( pParam ) == NULL );
+
+ int i = m_FlagParams.AddToTail( );
+ m_FlagParams[i] = pParam;
+
+ CDmeEditorAttributeInfo *pInfo = CreateElement< CDmeEditorAttributeInfo >( "flag param info", m_pVMTType->GetFileId() );
+ m_pVMTType->AddAttributeInfo( pParam, pInfo );
+ pInfo->m_bIsVisible = m_bFlagParamsVisible;
+ pInfo->m_Widget = NULL;
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+}
+
+void CVMTTool::AddToolParameter( const char *pParam, const char *pWidget, const char *pTextType )
+{
+ Assert( m_pVMTType->GetAttributeInfo( pParam ) == NULL );
+
+ int i = m_ToolParams.AddToTail( );
+ m_ToolParams[i] = pParam;
+
+ CDmeEditorAttributeInfo *pInfo = CreateElement< CDmeEditorAttributeInfo >( "tool param info", m_pVMTType->GetFileId() );
+ m_pVMTType->AddAttributeInfo( pParam, pInfo );
+ pInfo->m_bIsVisible = m_bToolParamsVisible;
+ pInfo->m_Widget = pWidget;
+ if ( pTextType )
+ {
+ pInfo->SetValue( "texttype", pTextType );
+ }
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+}
+
+void CVMTTool::RemoveAllFlagParameters()
+{
+ int nCount = m_FlagParams.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ RemoveShaderParameter( m_FlagParams[i] );
+ }
+ m_FlagParams.RemoveAll();
+}
+
+void CVMTTool::RemoveAllToolParameters()
+{
+ int nCount = m_ToolParams.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ RemoveShaderParameter( m_ToolParams[i] );
+ }
+ m_ToolParams.RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Create custom editors
+//-----------------------------------------------------------------------------
+void CVMTTool::InitEditorDict()
+{
+ CDmeEditorAttributeInfo *pInfo;
+
+ // FIXME: This eventually will move to an .fgd-like file.
+ g_pEditorTypeDict = CreateElement< CDmeEditorTypeDictionary >( "DmeEditorTypeDictionary", DMFILEID_INVALID );
+ m_toolElements.AddToTail( g_pEditorTypeDict->GetHandle() );
+
+ m_pVMTType = CreateElement< CDmeEditorType >( "vmt", DMFILEID_INVALID );
+ HideStandardFields( m_pVMTType, EDITOR_FIELD_NAME | EDITOR_FIELD_TYPE | EDITOR_FIELD_ID | EDITOR_FIELD_EDITORTYPE );
+ g_pEditorTypeDict->AddEditorType( m_pVMTType );
+ m_toolElements.AddToTail( m_pVMTType->GetHandle() );
+
+ // Create a picker for the shader name
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "shader name info", DMFILEID_INVALID );
+ m_pVMTType->AddAttributeInfo( "shader", pInfo );
+ pInfo->m_Widget = "shaderpicker";
+ pInfo->SetValue( "texttype", "shaderName" );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+// The Material menu
+//
+//-----------------------------------------------------------------------------
+class CVMTMaterialMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CVMTMaterialMenuButton, CToolMenuButton );
+public:
+ CVMTMaterialMenuButton( vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+};
+
+CVMTMaterialMenuButton::CVMTMaterialMenuButton( vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ AddMenuItem( "default", "#VMTSetToDefault", new KeyValues( "OnSetParamsToDefault" ), pActionSignalTarget );
+ SetMenu(m_pMenu);
+}
+
+void CVMTMaterialMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ int id;
+
+ CVMTDoc *pDoc = g_pVMTTool->GetDocument();
+ if ( pDoc )
+ {
+ id = m_Items.Find( "default" );
+ m_pMenu->SetItemEnabled( id, true );
+ }
+ else
+ {
+ id = m_Items.Find( "default" );
+ m_pMenu->SetItemEnabled( id, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// The View menu
+//
+//-----------------------------------------------------------------------------
+class CVMTViewMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CVMTViewMenuButton, CToolMenuButton );
+public:
+ CVMTViewMenuButton( vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+};
+
+CVMTViewMenuButton::CVMTViewMenuButton( vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ AddCheckableMenuItem( "properties", "#VMTProperties", new KeyValues( "OnToggleProperties" ), pActionSignalTarget );
+ AddCheckableMenuItem( "preview", "#VMTPreview", new KeyValues( "OnToggleVMTPreview" ), pActionSignalTarget );
+
+ AddSeparator();
+
+ AddCheckableMenuItem( "showflagparams", "#VMTShowFlags", new KeyValues( "OnShowFlags" ), pActionSignalTarget );
+ AddCheckableMenuItem( "showtoolparams", "#VMTShowToolParams", new KeyValues( "OnShowToolParams" ), pActionSignalTarget );
+
+ AddSeparator();
+
+ AddMenuItem( "defaultlayout", "#VMTViewDefault", new KeyValues( "OnDefaultLayout" ), pActionSignalTarget );
+
+ SetMenu(m_pMenu);
+}
+
+void CVMTViewMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ int id;
+
+ CVMTDoc *pDoc = g_pVMTTool->GetDocument();
+ if ( pDoc )
+ {
+ id = m_Items.Find( "properties" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ Panel *p;
+ p = g_pVMTTool->GetProperties();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+
+ id = m_Items.Find( "preview" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ p = g_pVMTTool->GetVMTPreview();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+
+ id = m_Items.Find( "showflagparams" );
+ m_pMenu->SetItemEnabled( id, true );
+ m_pMenu->SetMenuItemChecked( id, g_pVMTTool->IsFlagParamsVisible() );
+
+ id = m_Items.Find( "showtoolparams" );
+ m_pMenu->SetItemEnabled( id, true );
+ m_pMenu->SetMenuItemChecked( id, g_pVMTTool->IsToolParamsVisible() );
+ }
+ else
+ {
+ id = m_Items.Find( "properties" );
+ m_pMenu->SetItemEnabled( id, false );
+ id = m_Items.Find( "preview" );
+ m_pMenu->SetItemEnabled( id, false );
+ id = m_Items.Find( "showflagparams" );
+ m_pMenu->SetItemEnabled( id, false );
+ id = m_Items.Find( "showtoolparams" );
+ m_pMenu->SetItemEnabled( id, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the menu bar
+//-----------------------------------------------------------------------------
+vgui::MenuBar *CVMTTool::CreateMenuBar( CBaseToolSystem *pParent )
+{
+ m_pMenuBar = new CToolFileMenuBar( pParent, "VMTMenuBar" );
+
+ // Sets info in the menu bar
+ char title[ 64 ];
+ ComputeMenuBarTitle( title, sizeof( title ) );
+ m_pMenuBar->SetInfo( title );
+ m_pMenuBar->SetToolName( GetToolName() );
+ UpdateMenuBar();
+
+ // Add menu buttons
+ CToolMenuButton *pFileButton = CreateToolFileMenuButton( m_pMenuBar, "File", "&File", GetActionTarget(), this );
+ CToolMenuButton *pEditButton = CreateToolEditMenuButton( m_pMenuBar, "Edit", "&Edit", GetActionTarget() );
+ CToolMenuButton *pMaterialButton = new CVMTMaterialMenuButton( m_pMenuBar, "Material", "&Material", GetActionTarget() );
+ CToolMenuButton *pSwitchButton = CreateToolSwitchMenuButton( m_pMenuBar, "Switcher", "&Tools", GetActionTarget() );
+ CVMTViewMenuButton *pViewButton = new CVMTViewMenuButton( m_pMenuBar, "View", "&View", GetActionTarget() );
+
+ m_pMenuBar->AddButton( pFileButton );
+ m_pMenuBar->AddButton( pEditButton );
+ m_pMenuBar->AddButton( pMaterialButton );
+ m_pMenuBar->AddButton( pViewButton );
+ m_pMenuBar->AddButton( pSwitchButton );
+
+ return m_pMenuBar;
+}
+
+
+//-----------------------------------------------------------------------------
+// Updates the menu bar based on the current file
+//-----------------------------------------------------------------------------
+void CVMTTool::UpdateMenuBar( )
+{
+ if ( !m_pDoc )
+ {
+ m_pMenuBar->SetFileName( "#VMTNoFile" );
+ return;
+ }
+
+ if ( m_pDoc->IsDirty() )
+ {
+ char sz[ 512 ];
+ Q_snprintf( sz, sizeof( sz ), "* %s", m_pDoc->GetFileName() );
+ m_pMenuBar->SetFileName( sz );
+ }
+ else
+ {
+ m_pMenuBar->SetFileName( m_pDoc->GetFileName() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from IFileMenuCallbacks
+//-----------------------------------------------------------------------------
+int CVMTTool::GetFileMenuItemsEnabled( )
+{
+ int nFlags;
+ if ( !m_pDoc )
+ {
+ nFlags = FILE_NEW | FILE_OPEN | FILE_RECENT | FILE_CLEAR_RECENT | FILE_EXIT;
+ }
+ else
+ {
+ nFlags = FILE_ALL;
+ }
+
+ if ( m_RecentFiles.IsEmpty() )
+ {
+ nFlags &= ~(FILE_RECENT | FILE_CLEAR_RECENT);
+ }
+ return nFlags;
+}
+
+void CVMTTool::AddRecentFilesToMenu( vgui::Menu *pMenu )
+{
+ m_RecentFiles.AddToMenu( pMenu, GetActionTarget(), "OnRecent" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the file name for perforce
+//-----------------------------------------------------------------------------
+bool CVMTTool::GetPerforceFileName( char *pFileName, int nMaxLen )
+{
+ if ( !m_pDoc )
+ return false;
+ Q_strncpy( pFileName, m_pDoc->GetFileName(), nMaxLen );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get a new scheme to be applied to this tool
+//-----------------------------------------------------------------------------
+vgui::HScheme CVMTTool::GetToolScheme()
+{
+ return vgui::scheme()->LoadSchemeFromFile( "Resource/BoxRocket.res", "BoxRocket" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates the action menu
+//-----------------------------------------------------------------------------
+vgui::Menu *CVMTTool::CreateActionMenu( vgui::Panel *pParent )
+{
+ vgui::Menu *pActionMenu = new Menu( pParent, "ActionMenu" );
+ pActionMenu->AddMenuItem( "#ToolHide", new KeyValues( "Command", "command", "HideActionMenu" ), GetActionTarget() );
+ return pActionMenu;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+void CVMTTool::OnExit()
+{
+ // Throw up a "save" dialog?
+ enginetools->Command( "quit\n" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Handle commands from the action menu and other menus
+//-----------------------------------------------------------------------------
+void CVMTTool::OnCommand( const char *cmd )
+{
+ if ( !V_stricmp( cmd, "HideActionMenu" ) )
+ {
+ if ( GetActionMenu() )
+ {
+ GetActionMenu()->SetVisible( false );
+ }
+ }
+ else if ( !V_stricmp( cmd, "OnUndo" ) )
+ {
+ OnUndo();
+ }
+ else if ( !V_stricmp( cmd, "OnRedo" ) )
+ {
+ OnRedo();
+ }
+ else if ( !V_stricmp( cmd, "OnDescribeUndo" ) )
+ {
+ OnDescribeUndo();
+ }
+ else if ( const char *pSuffix = StringAfterPrefix( cmd, "OnRecent" ) )
+ {
+ int idx = Q_atoi( pSuffix );
+ g_pVMTTool->OpenFileFromHistory( idx, cmd );
+ }
+ else if ( const char *pSuffix = StringAfterPrefix( cmd, "OnTool" ) )
+ {
+ int idx = Q_atoi( pSuffix );
+ enginetools->SwitchToTool( idx );
+ }
+ else
+ {
+ BaseClass::OnCommand( cmd );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Messages from the engine
+//-----------------------------------------------------------------------------
+void CVMTTool::PostMessage( HTOOLHANDLE hEntity, KeyValues *message )
+{
+ if ( !Q_stricmp( message->GetName(), "EditMaterial" ) )
+ {
+ const char *pMaterialName = message->GetString( "material", "debug/debugempty" );
+
+ char pLocalPath[ MAX_PATH ];
+ char pAbsPath[ MAX_PATH ];
+ if ( pMaterialName[0] == '/' && pMaterialName[1] == '/' && pMaterialName[2] != '/' )
+ {
+ Q_strncpy( pAbsPath, pMaterialName, sizeof(pAbsPath) );
+ Q_DefaultExtension( pAbsPath, ".vmt", sizeof(pAbsPath) );
+ }
+ else
+ {
+ Q_snprintf( pLocalPath, sizeof(pLocalPath), "materials/%s", pMaterialName );
+ Q_DefaultExtension( pLocalPath, ".vmt", sizeof(pLocalPath) );
+ g_pFileSystem->RelativePathToFullPath( pLocalPath, "GAME", pAbsPath, sizeof(pAbsPath) );
+ }
+
+ Q_FixSlashes( pAbsPath );
+ OpenSpecificFile( pAbsPath );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get notified when files are saved/loaded
+//-----------------------------------------------------------------------------
+void CVMTTool::OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues )
+{
+ if ( bWroteFile )
+ {
+ OnMarkNotDirty();
+ }
+
+ if ( !pContextKeyValues )
+ return;
+
+ if ( state != FileOpenStateMachine::SUCCESSFUL )
+ return;
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnNew" ) )
+ {
+ PerformNew();
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnClose" ) )
+ {
+ OnCloseNoSave();
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnQuit" ) )
+ {
+ OnCloseNoSave();
+ vgui::ivgui()->PostMessage( GetVPanel(), new KeyValues( "OnExit" ), 0 );
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Called by SaveFile to allow clients to set up the save dialog
+//-----------------------------------------------------------------------------
+void CVMTTool::SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ // Compute starting directory
+ char pStartingDir[ MAX_PATH ];
+ GetModSubdirectory( "materials", pStartingDir, sizeof(pStartingDir) );
+
+ if ( bOpenFile )
+ {
+ pDialog->SetTitle( "Open Material .VMT File", true );
+ }
+ else
+ {
+ pDialog->SetTitle( "Save Material .VMT File As", true );
+ }
+
+ pDialog->SetStartDirectoryContext( "vmt_session", pStartingDir );
+ pDialog->AddFilter( "*.vmt", "VMT (*.vmt)", true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called by SaveFile to allow clients to actually write the file out
+//-----------------------------------------------------------------------------
+bool CVMTTool::OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ OnCloseNoSave();
+ if ( !LoadDocument( pFileName ) )
+ return false;
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ UpdateMenuBar();
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Called by SaveFile to allow clients to actually write the file out
+//-----------------------------------------------------------------------------
+bool CVMTTool::OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ if ( !m_pDoc )
+ return true;
+
+ m_pDoc->SetFileName( pFileName );
+ if ( !m_pDoc->SaveToFile( ) )
+ return false;
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ UpdateMenuBar();
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Command handlers
+//-----------------------------------------------------------------------------
+void CVMTTool::PerformNew()
+{
+ OnCloseNoSave();
+ NewDocument();
+}
+
+void CVMTTool::OnNew()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetFileName(), "vmt", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnNew" ) );
+ return;
+ }
+ PerformNew();
+}
+
+void CVMTTool::OnOpen( )
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetFileName();
+ }
+
+ OpenFile( "vmt", pSaveFileName, "vmt", nFlags );
+}
+
+void CVMTTool::OnSave()
+{
+ if ( m_pDoc )
+ {
+ SaveFile( m_pDoc->GetFileName(), "vmt", FOSM_SHOW_PERFORCE_DIALOGS );
+ }
+}
+
+void CVMTTool::OnSaveAs()
+{
+ if ( m_pDoc )
+ {
+ SaveFile( NULL, "vmt", FOSM_SHOW_PERFORCE_DIALOGS );
+ }
+}
+
+void CVMTTool::OnClose()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetFileName(), "vmt", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnClose" ) );
+ return;
+ }
+
+ OnCloseNoSave();
+}
+
+void CVMTTool::OnCloseNoSave()
+{
+ DestroyTools();
+
+ if ( m_pDoc )
+ {
+ CAppNotifyScopeGuard sg( "CVMTTool::OnCloseNoSave", NOTIFY_CHANGE_OTHER );
+
+ delete m_pDoc;
+ m_pDoc = NULL;
+
+ if ( m_hProperties )
+ {
+ m_hProperties->SetObject( NULL );
+ }
+ }
+
+ UpdateMenuBar( );
+}
+
+void CVMTTool::OnMarkNotDirty()
+{
+ if ( m_pDoc )
+ {
+ m_pDoc->SetDirty( false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Open a specific file
+//-----------------------------------------------------------------------------
+void CVMTTool::OpenSpecificFile( const char *pFileName )
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc )
+ {
+ // File is already open
+ if ( !Q_stricmp( m_pDoc->GetFileName(), pFileName ) )
+ return;
+
+ if ( m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetFileName();
+ }
+ }
+
+ OpenFile( pFileName, "vmt", pSaveFileName, "vmt", nFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the save document query dialog
+//-----------------------------------------------------------------------------
+void CVMTTool::OpenFileFromHistory( int slot, const char *pCommand )
+{
+ const char *pFileName = m_RecentFiles.GetFile( slot );
+ if ( !pFileName )
+ return;
+ OpenSpecificFile( pFileName );
+}
+
+bool CVMTTool::CanQuit()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ // Show Save changes Yes/No/Cancel and re-quit if hit yes/no
+ SaveFile( m_pDoc->GetFileName(), "vmt", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnQuit" ) );
+ return false;
+ }
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Various command handlers related to the Edit menu
+//-----------------------------------------------------------------------------
+void CVMTTool::OnUndo()
+{
+ CDisableUndoScopeGuard guard;
+ g_pDataModel->Undo();
+}
+
+void CVMTTool::OnRedo()
+{
+ CDisableUndoScopeGuard guard;
+ g_pDataModel->Redo();
+}
+
+void CVMTTool::OnDescribeUndo()
+{
+ CUtlVector< UndoInfo_t > list;
+ g_pDataModel->GetUndoInfo( list );
+
+ Msg( "%i operations in stack\n", list.Count() );
+
+ for ( int i = list.Count() - 1; i >= 0; --i )
+ {
+ UndoInfo_t& entry = list[ i ];
+ if ( entry.terminator )
+ {
+ Msg( "[ '%s' ] - %i operations\n", entry.undo, entry.numoperations );
+ }
+
+ Msg( " +%s\n", entry.desc );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from IVMTDocCallback
+//-----------------------------------------------------------------------------
+void CVMTTool::OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ UpdateMenuBar();
+ if ( ( nNotifySource != NOTIFY_SOURCE_PROPERTIES_TREE ) && m_hProperties.Get() )
+ {
+ m_hProperties->Refresh();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+// Output : CVMTDoc
+//-----------------------------------------------------------------------------
+CVMTDoc *CVMTTool::GetDocument()
+{
+ return m_pDoc;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+// Output : virtual CBasePropertiesContainer
+//-----------------------------------------------------------------------------
+CBasePropertiesContainer *CVMTTool::GetProperties()
+{
+ return m_hProperties.Get();
+}
+
+CVMTPanel *CVMTTool::GetVMTPreview()
+{
+ return m_hVMTPreview.Get();
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the tools
+//-----------------------------------------------------------------------------
+void CVMTTool::InitTools()
+{
+ ShowElementProperties();
+
+ // FIXME: There are no tool windows here; how should this work?
+ // These panels are saved
+ windowposmgr->RegisterPanel( "properties", m_hProperties, false );
+ windowposmgr->RegisterPanel( "vmtpanel", m_hVMTPreview, false );
+
+ if ( !windowposmgr->LoadPositions( "cfg/vmt.txt", this, &m_ToolWindowFactory, "VMT" ) )
+ {
+ OnDefaultLayout();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads up a new document
+//-----------------------------------------------------------------------------
+bool CVMTTool::LoadDocument( char const *pDocName )
+{
+ Assert( !m_pDoc );
+
+ DestroyTools();
+
+ m_pDoc = new CVMTDoc( this );
+ if ( !m_pDoc->LoadFromFile( pDocName ) )
+ {
+ delete m_pDoc;
+ m_pDoc = NULL;
+ Warning( "Fatal error loading '%s'\n", pDocName );
+ return false;
+ }
+
+ CreateTools( m_pDoc );
+ InitTools();
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads up a new document
+//-----------------------------------------------------------------------------
+void CVMTTool::NewDocument( )
+{
+ Assert( !m_pDoc );
+
+ m_pDoc = new CVMTDoc( this );
+ m_pDoc->CreateNew( );
+
+ CreateTools( m_pDoc );
+ UpdateMenuBar( );
+ InitTools();
+}
+
+
+//-----------------------------------------------------------------------------
+// Shows element properties
+//-----------------------------------------------------------------------------
+void CVMTTool::ShowElementProperties( )
+{
+ if ( !m_pDoc )
+ return;
+
+ if ( !m_pDoc->GetRootObject() )
+ return;
+
+ // It should already exist
+ Assert( m_hProperties.Get() );
+ if ( m_hProperties.Get() )
+ {
+ m_hProperties->SetObject( m_pDoc->GetRootObject() );
+ }
+}
+
+void CVMTTool::DestroyTools()
+{
+ windowposmgr->SavePositions( "cfg/vmt.txt", "VMT" );
+
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+
+ UnregisterAllToolWindows();
+ if ( m_hProperties.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hProperties.Get() );
+ delete m_hProperties.Get();
+ m_hProperties = NULL;
+ }
+ if ( m_hVMTPreview.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hVMTPreview.Get() );
+ delete m_hVMTPreview.Get();
+ m_hVMTPreview = NULL;
+ }
+}
+
+void CVMTTool::CreateTools( CVMTDoc *doc )
+{
+ if ( !m_hProperties.Get() )
+ {
+ m_hProperties = new CBasePropertiesContainer( NULL, m_pDoc, g_pEditorTypeDict );
+ }
+ if ( !m_hVMTPreview.Get() )
+ {
+ m_hVMTPreview = new CVMTPanel( NULL, "VMT Preview" );
+ SETUP_PANEL( m_hVMTPreview.Get() );
+ m_hVMTPreview->SetMaterial( m_pDoc->GetPreviewMaterial() );
+ }
+ RegisterToolWindow( m_hProperties );
+ RegisterToolWindow( m_hVMTPreview );
+}
+
+void CVMTTool::ShowToolWindow( Panel *tool, char const *toolName, bool visible )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL && visible )
+ {
+ m_ToolWindowFactory.InstanceToolWindow( this, false, tool, toolName, false );
+ }
+ else if ( !visible )
+ {
+ ToolWindow *tw = dynamic_cast< ToolWindow * >( tool->GetParent()->GetParent() );
+ Assert( tw );
+ tw->RemovePage( tool );
+ }
+}
+
+void CVMTTool::ToggleToolWindow( Panel *tool, char const *toolName )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL )
+ {
+ ShowToolWindow( tool, toolName, true );
+ }
+ else
+ {
+ ShowToolWindow( tool, toolName, false );
+ }
+}
+
+void CVMTTool::DestroyToolContainers()
+{
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+}
+
+void CVMTTool::OnDefaultLayout()
+{
+ int y = m_pMenuBar->GetTall();
+
+ int usew, useh;
+ GetSize( usew, useh );
+
+ DestroyToolContainers();
+
+ Assert( ToolWindow::GetToolWindowCount() == 0 );
+
+ CBasePropertiesContainer *properties = GetProperties();
+ CVMTPanel *pVMTPreview = GetVMTPreview();
+
+ // Need three containers
+ ToolWindow *pPropertyWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, properties, "#VMTProperties", false );
+ ToolWindow *pVMTPreviewWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, pVMTPreview, "#VMTPreview", false );
+
+ int halfScreen = usew / 2;
+ int bottom = useh - y;
+ int sy = (bottom - y) / 2;
+
+ SetMiniViewportBounds( halfScreen, y, halfScreen, sy - y );
+ pPropertyWindow->SetBounds( 0, y, halfScreen, bottom );
+ pVMTPreviewWindow->SetBounds( halfScreen, sy, halfScreen, bottom - sy );
+}
+
+void CVMTTool::OnToggleProperties()
+{
+ if ( m_hProperties.Get() )
+ {
+ ToggleToolWindow( m_hProperties.Get(), "#VMTProperties" );
+ }
+}
+
+void CVMTTool::OnToggleVMTPreview()
+{
+ if ( m_hVMTPreview.Get() )
+ {
+ ToggleToolWindow( m_hVMTPreview.Get(), "#VMTPreview" );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Show/hide tool params + flags
+//-----------------------------------------------------------------------------
+void CVMTTool::OnShowFlags()
+{
+ m_bFlagParamsVisible = !m_bFlagParamsVisible;
+
+ int nCount = m_FlagParams.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeEditorAttributeInfo *pInfo = m_pVMTType->GetAttributeInfo( m_FlagParams[i] );
+ Assert( pInfo );
+ pInfo->m_bIsVisible = m_bFlagParamsVisible;
+ }
+ if ( m_hProperties.Get() )
+ {
+ m_hProperties->Refresh();
+ }
+}
+
+void CVMTTool::OnShowToolParams()
+{
+ m_bToolParamsVisible = !m_bToolParamsVisible;
+
+ int nCount = m_ToolParams.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeEditorAttributeInfo *pInfo = m_pVMTType->GetAttributeInfo( m_ToolParams[i] );
+ Assert( pInfo );
+ pInfo->m_bIsVisible = m_bToolParamsVisible;
+ }
+ if ( m_hProperties.Get() )
+ {
+ m_hProperties->Refresh();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets shader parameters to the default for that shader
+//-----------------------------------------------------------------------------
+void CVMTTool::OnSetParamsToDefault()
+{
+ if ( m_pDoc )
+ {
+ m_pDoc->SetParamsToDefault();
+ }
+}
+
+char const *CVMTTool::GetLogoTextureName()
+{
+ return "vgui/tools/vmt/vmt_logo";
+} \ No newline at end of file
diff --git a/tools/vmt/vmttool.h b/tools/vmt/vmttool.h
new file mode 100644
index 0000000..28e5ffe
--- /dev/null
+++ b/tools/vmt/vmttool.h
@@ -0,0 +1,50 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: VMT tool; main UI smarts class
+//
+//=============================================================================
+
+#ifndef VMTTOOL_H
+#define VMTTOOL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CDmeEditorTypeDictionary;
+
+
+//-----------------------------------------------------------------------------
+// Singleton interfaces
+//-----------------------------------------------------------------------------
+extern CDmeEditorTypeDictionary *g_pEditorTypeDict;
+
+
+//-----------------------------------------------------------------------------
+// Allows the doc to call back into the VMT editor tool
+//-----------------------------------------------------------------------------
+class IVMTDocCallback
+{
+public:
+ // Called by the doc when the data changes
+ virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags ) = 0;
+
+ // Update the editor dict based on the current material parameters
+ virtual void AddShaderParameter( const char *pParam, const char *pWidget, const char *pTextType ) = 0;
+
+ // Update the editor dict based on the current material parameters
+ virtual void RemoveShaderParameter( const char *pParam ) = 0;
+
+ // Adds flags, tool parameters
+ virtual void AddFlagParameter( const char *pParam ) = 0;
+ virtual void AddToolParameter( const char *pParam, const char *pWidget = NULL, const char *pTextType = NULL ) = 0;
+ virtual void RemoveAllFlagParameters() = 0;
+ virtual void RemoveAllToolParameters() = 0;
+};
+
+
+#endif // VMTTOOL_H