diff options
Diffstat (limited to 'tools')
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", + ¢er.x, ¢er.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 |