diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /tools/commedit | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'tools/commedit')
| -rw-r--r-- | tools/commedit/commedit.vpc | 64 | ||||
| -rw-r--r-- | tools/commedit/commeditdoc.cpp | 443 | ||||
| -rw-r--r-- | tools/commedit/commeditdoc.h | 92 | ||||
| -rw-r--r-- | tools/commedit/commedittool.cpp | 1284 | ||||
| -rw-r--r-- | tools/commedit/commedittool.h | 231 | ||||
| -rw-r--r-- | tools/commedit/commentarynodebrowserpanel.cpp | 283 | ||||
| -rw-r--r-- | tools/commedit/commentarynodebrowserpanel.h | 67 | ||||
| -rw-r--r-- | tools/commedit/commentarypropertiespanel.cpp | 458 | ||||
| -rw-r--r-- | tools/commedit/commentarypropertiespanel.h | 113 | ||||
| -rw-r--r-- | tools/commedit/dmecommentarynodeentity.cpp | 339 | ||||
| -rw-r--r-- | tools/commedit/dmecommentarynodeentity.h | 100 | ||||
| -rw-r--r-- | tools/commedit/entityreportpanel.cpp | 581 |
12 files changed, 4055 insertions, 0 deletions
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 |