mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-23 14:46:53 +00:00
2005 lines
44 KiB
C++
2005 lines
44 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//
|
|
//=============================================================================//
|
|
#include "cbase.h"
|
|
#include "workspacemanager.h"
|
|
#include "workspacebrowser.h"
|
|
#include "workspace.h"
|
|
#include "statuswindow.h"
|
|
#include "SoundEmitterSystem/isoundemittersystembase.h"
|
|
#include "drawhelper.h"
|
|
#include "InputProperties.h"
|
|
#include "filesystem.h"
|
|
#include "cmdlib.h"
|
|
#include "project.h"
|
|
#include "scene.h"
|
|
#include <KeyValues.h>
|
|
#include "utlbuffer.h"
|
|
#include "iscenemanagersound.h"
|
|
#include "soundentry.h"
|
|
#include "vcdfile.h"
|
|
#include "soundbrowser.h"
|
|
#include "wavebrowser.h"
|
|
#include "VSSProperties.h"
|
|
#include "resource.h"
|
|
#include "soundproperties.h"
|
|
#include "waveproperties.h"
|
|
#include "wavefile.h"
|
|
#include "ifileloader.h"
|
|
#include "MultipleRequest.h"
|
|
#include <vgui/ILocalize.h>
|
|
#include "tier3/tier3.h"
|
|
|
|
char g_appTitle[] = "Source Engine SceneManager";
|
|
static char g_appTitleFmt[] = "%s - SceneManager Workspace (%s)";
|
|
static char g_appTitleFmtModified[] = "%s * - SceneManager Workspace (%s)";
|
|
|
|
#define RECENT_FILES_FILE "scenemanager.rf"
|
|
|
|
enum
|
|
{
|
|
// Menu options
|
|
IDC_WSM_FILE_EXIT = 1000,
|
|
|
|
IDC_WSM_FILE_WS_NEW,
|
|
IDC_WSM_FILE_WS_OPEN,
|
|
IDC_WSM_FILE_WS_CLOSE,
|
|
IDC_WSM_FILE_WS_SAVE,
|
|
|
|
IDC_WSM_FILE_WS_REFRESH,
|
|
|
|
IDC_WSM_FILE_WS_VSSPROPERTIES,
|
|
IDC_WSM_FILE_WS_CHECKOUT,
|
|
IDC_WSM_FILE_WS_CHECKIN,
|
|
|
|
IDC_WSM_FILE_SCENE_NEW, // + prompt for add to active project
|
|
|
|
IDC_WSM_PROJECT_PRJ_NEW, // + Prompt for add to workspace
|
|
|
|
IDC_WSM_PROJECT_PRJ_INSERT,
|
|
IDC_WSM_PROJECT_PRJ_REMOVE,
|
|
IDC_WSM_PROJECT_PRJ_MODIFYCOMMENTS,
|
|
|
|
IDC_WSM_PROJECT_SCENE_NEW,
|
|
IDC_WSM_SCENE_REMOVE,
|
|
|
|
IDC_WSM_SOUNDENTRY_PLAY,
|
|
IDC_WSM_SOUNDENTRY_TOGGLEVOICEDUCK,
|
|
IDC_WSM_SOUNDENTRY_EDITTEXT,
|
|
IDC_WSM_SOUNDENTRY_SHOWINBROWSERS,
|
|
IDC_WSM_SOUNDENTRY_PROPERTIES,
|
|
|
|
IDC_WSM_SCENE_VCD_ADD,
|
|
IDC_WSM_SCENE_VCD_REMOVE,
|
|
IDC_WSM_SCENE_EDIT_COMMENTS,
|
|
|
|
IDC_WSM_VCD_EDIT_COMMENTS,
|
|
|
|
IDC_WSM_SELECTION_CHECKOUT,
|
|
IDC_WSM_SELECTION_CHECKIN,
|
|
|
|
IDC_WSM_SELECTION_MOVEUP,
|
|
IDC_WSM_SELECTION_MOVEDOWN,
|
|
|
|
IDC_WSM_WAVEFILE_PROPERTIES,
|
|
|
|
// Controls
|
|
IDC_WS_BROWSER,
|
|
IDC_WS_SOUNDBROWSER,
|
|
IDC_WS_WAVEBROWSER,
|
|
|
|
// These should be the final entriex
|
|
IDC_WSM_FILE_RECENT_WORKSPACE_START = 1500,
|
|
IDC_WSM_FILE_RECENT_WORKSPACE_END = 1510,
|
|
|
|
IDC_WSM_OPTIONS_LANGUAGESTART = 1600,
|
|
IDC_WSM_OPTIONS_LANGUAGEEND = 1600 + CC_NUM_LANGUAGES,
|
|
};
|
|
|
|
static CWorkspaceManager *g_pManager = NULL;
|
|
CWorkspaceManager *GetWorkspaceManager()
|
|
{
|
|
Assert( g_pManager );
|
|
return g_pManager;
|
|
}
|
|
|
|
class CWorkspaceWorkArea : public mxWindow
|
|
{
|
|
public:
|
|
CWorkspaceWorkArea( mxWindow *parent )
|
|
: mxWindow( parent, 0, 0, 0, 0, "" )
|
|
{
|
|
SceneManager_AddWindowStyle( this, WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
|
|
}
|
|
|
|
virtual void redraw()
|
|
{
|
|
CDrawHelper helper( this, RGB( 200, 200, 200 ) );
|
|
}
|
|
};
|
|
|
|
CWorkspaceManager::CWorkspaceManager()
|
|
: mxWindow (0, 0, 0, 0, 0, g_appTitle, mxWindow::Normal)
|
|
{
|
|
m_lEnglishCaptionsFileChangeTime = -1L;
|
|
m_nLanguageId = CC_ENGLISH;
|
|
|
|
g_pManager = this;
|
|
|
|
g_pStatusWindow = new CStatusWindow( this, 0, 0, 1024, 150, "" );
|
|
g_pStatusWindow->setVisible( true );
|
|
|
|
m_pWorkArea = new CWorkspaceWorkArea( this );
|
|
|
|
Con_Printf( "Initializing\n" );
|
|
|
|
Con_Printf( "CSoundEmitterSystemBase::Init()\n" );
|
|
|
|
m_nRecentMenuItems = 0;
|
|
|
|
// create menu stuff
|
|
m_pMenuBar = new mxMenuBar (this);
|
|
m_pFileMenu = new mxMenu ();
|
|
m_pProjectMenu = new mxMenu ();
|
|
m_pOptionsMenu = new mxMenu();
|
|
|
|
{
|
|
m_pMenuCloseCaptionLanguages = new mxMenu();
|
|
|
|
for ( int i = 0; i < CC_NUM_LANGUAGES; i++ )
|
|
{
|
|
int id = IDC_WSM_OPTIONS_LANGUAGESTART + i;
|
|
m_pMenuCloseCaptionLanguages->add( CSentence::NameForLanguage( i ), id );
|
|
}
|
|
// Check the first item
|
|
m_pMenuCloseCaptionLanguages->setChecked( IDC_WSM_OPTIONS_LANGUAGESTART + CC_ENGLISH, true );
|
|
m_pOptionsMenu->addMenu( "CC Language", m_pMenuCloseCaptionLanguages );
|
|
|
|
}
|
|
|
|
m_pMenuBar->addMenu ("File", m_pFileMenu );
|
|
m_pMenuBar->addMenu( "Project", m_pProjectMenu );
|
|
m_pMenuBar->addMenu ( "Options", m_pOptionsMenu );
|
|
|
|
CreateFileMenu( m_pFileMenu );
|
|
CreateProjectMenu( m_pProjectMenu );
|
|
|
|
setMenuBar ( m_pMenuBar );
|
|
|
|
Con_Printf( "Creating browser\n" );
|
|
|
|
m_pBrowser = new CWorkspaceBrowser( m_pWorkArea, this, IDC_WS_BROWSER );
|
|
|
|
m_pSoundBrowser = NULL;
|
|
m_pWaveBrowser = NULL;
|
|
|
|
int w = 1280;
|
|
setBounds (10, 10, w, 960);
|
|
|
|
setVisible (true);
|
|
|
|
Con_Printf( "Creating wave browser\n" );
|
|
|
|
m_pWaveBrowser = new CWaveBrowser( m_pWorkArea, this, IDC_WS_WAVEBROWSER );
|
|
|
|
Con_Printf( "Creating sound browser\n" );
|
|
|
|
m_pSoundBrowser = new CSoundBrowser( m_pWorkArea, this, IDC_WS_SOUNDBROWSER );
|
|
|
|
GetBrowser()->SetWorkspace( NULL );
|
|
|
|
// See if command line requested workspace
|
|
|
|
// Default layout
|
|
PerformLayout( true );
|
|
|
|
LoadRecentFilesMenuFromDisk();
|
|
}
|
|
|
|
CWorkspaceManager::~CWorkspaceManager()
|
|
{
|
|
}
|
|
|
|
bool CWorkspaceManager::Closing()
|
|
{
|
|
Con_Printf( "Checking for sound script changes...\n" );
|
|
|
|
MultipleRequestChangeContext();
|
|
|
|
// Save any changed sound script files
|
|
int c = g_pSoundEmitterSystem->GetNumSoundScripts();
|
|
for ( int i = 0; i < c; i++ )
|
|
{
|
|
if ( !g_pSoundEmitterSystem->IsSoundScriptDirty( i ) )
|
|
continue;
|
|
|
|
char const *scriptname = g_pSoundEmitterSystem->GetSoundScriptName( i );
|
|
if ( !scriptname )
|
|
continue;
|
|
|
|
Assert( filesystem->FileExists( scriptname ) );
|
|
|
|
bool save = true;
|
|
|
|
if ( filesystem->FileExists( scriptname ) )
|
|
{
|
|
if ( !filesystem->IsFileWritable( scriptname ) )
|
|
{
|
|
int retval = MultipleRequest( va( "Check out '%s'?", scriptname ));
|
|
// Cancel
|
|
if ( retval == 2 )
|
|
return false;
|
|
|
|
if ( retval == 0 )
|
|
{
|
|
VSS_Checkout( scriptname );
|
|
|
|
if ( !filesystem->IsFileWritable( scriptname ) )
|
|
{
|
|
mxMessageBox( NULL, va( "Aborting shutdown, %s, not writable!!", scriptname ), g_appTitle, MX_MB_OK );
|
|
return false;
|
|
}
|
|
}
|
|
else if ( retval == 1 )
|
|
{
|
|
// Don't save
|
|
save = false;
|
|
}
|
|
}
|
|
|
|
if ( filesystem->IsFileWritable( scriptname ) )
|
|
{
|
|
int retval = mxMessageBox( NULL, va( "Save changes to out '%s'?", scriptname ), g_appTitle, MX_MB_YESNOCANCEL );
|
|
// Cancel
|
|
if ( retval == 2 )
|
|
return false;
|
|
|
|
if ( retval == 0 )
|
|
{
|
|
if ( !filesystem->IsFileWritable( scriptname ) )
|
|
{
|
|
mxMessageBox( NULL, va( "Aborting shutdown, %s, not writable!!", scriptname ), g_appTitle, MX_MB_OK );
|
|
return false;
|
|
}
|
|
}
|
|
else if ( retval == 1 )
|
|
{
|
|
// Skip changes!!!
|
|
save = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Try and save it
|
|
if ( !save )
|
|
continue;
|
|
|
|
g_pSoundEmitterSystem->SaveChangesToSoundScript( i );
|
|
}
|
|
|
|
return CloseWorkspace();
|
|
}
|
|
|
|
void CWorkspaceManager::OnDelete()
|
|
{
|
|
SaveRecentFilesMenuToDisk();
|
|
}
|
|
|
|
void CWorkspaceManager::CreateFileMenu( mxMenu *m )
|
|
{
|
|
m->add ("&New Workspace", IDC_WSM_FILE_WS_NEW );
|
|
m->addSeparator();
|
|
m->add ("Open &Workspace...", IDC_WSM_FILE_WS_OPEN );
|
|
m->add ("Sa&ve Workspace", IDC_WSM_FILE_WS_SAVE );
|
|
m->add ("Close Wor&kspace", IDC_WSM_FILE_WS_CLOSE );
|
|
m->addSeparator();
|
|
m->add ("&Create New Scene...", IDC_WSM_FILE_SCENE_NEW );
|
|
m->addSeparator();
|
|
|
|
m->add( "V&SS Properties...", IDC_WSM_FILE_WS_VSSPROPERTIES );
|
|
m->addSeparator();
|
|
|
|
m->add( "Refresh\tF5", IDC_WSM_FILE_WS_REFRESH );
|
|
|
|
m->addSeparator();
|
|
|
|
m_pRecentFileMenu = new mxMenu ();
|
|
m->addMenu ("Recent Files", m_pRecentFileMenu);
|
|
|
|
m->addSeparator();
|
|
m->add ("E&xit", IDC_WSM_FILE_EXIT );
|
|
}
|
|
|
|
void CWorkspaceManager::UpdateMenus()
|
|
{
|
|
CWorkspace *ws = GetBrowser()->GetWorkspace();
|
|
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
|
|
bool hasworkspace = ws != NULL ? true : false;
|
|
//bool workspacedirty = ws && ws->IsDirty() ? true : false;
|
|
bool hasproject = item && item->GetProject() ? true : false;
|
|
|
|
m_pMenuBar->setEnabled( IDC_WSM_FILE_WS_SAVE, true );
|
|
m_pMenuBar->setEnabled( IDC_WSM_FILE_WS_CLOSE, hasworkspace );
|
|
|
|
|
|
if ( hasproject )
|
|
{
|
|
m_pMenuBar->modify( IDC_WSM_FILE_SCENE_NEW, IDC_WSM_FILE_SCENE_NEW, va( "&Create Scene in '%s'", item->GetProject()->GetName() ) );
|
|
}
|
|
else
|
|
{
|
|
m_pMenuBar->modify( IDC_WSM_FILE_SCENE_NEW, IDC_WSM_FILE_SCENE_NEW, "&Create New Scene..." );
|
|
}
|
|
m_pMenuBar->setEnabled( IDC_WSM_FILE_SCENE_NEW, hasproject );
|
|
|
|
}
|
|
|
|
void CWorkspaceManager::CreateProjectMenu( mxMenu *m )
|
|
{
|
|
m->add ("Create New Project...", IDC_WSM_PROJECT_PRJ_NEW );
|
|
m->addSeparator();
|
|
m->add ("Insert Project...", IDC_WSM_PROJECT_PRJ_INSERT );
|
|
m->add ("Remove Project...", IDC_WSM_PROJECT_PRJ_REMOVE );
|
|
m->addSeparator();
|
|
m->add ("Properties...", IDC_WSM_PROJECT_PRJ_MODIFYCOMMENTS );
|
|
}
|
|
|
|
CWorkspaceBrowser *CWorkspaceManager::GetBrowser()
|
|
{
|
|
return m_pBrowser;
|
|
}
|
|
|
|
CSoundBrowser *CWorkspaceManager::GetSoundBrowser()
|
|
{
|
|
return m_pSoundBrowser;
|
|
}
|
|
|
|
CWaveBrowser *CWorkspaceManager::GetWaveBrowser()
|
|
{
|
|
return m_pWaveBrowser;
|
|
}
|
|
|
|
int CWorkspaceManager::GetMaxRecentFiles() const
|
|
{
|
|
return IDC_WSM_FILE_RECENT_WORKSPACE_END - IDC_WSM_FILE_RECENT_WORKSPACE_START;
|
|
}
|
|
|
|
#define MAX_FPS 250.0f
|
|
#define MIN_TIMESTEP ( 1.0f / MAX_FPS )
|
|
|
|
double realtime = 0.0f;
|
|
|
|
void CWorkspaceManager::Think( float dt )
|
|
{
|
|
sound->Update( dt );
|
|
int c = fileloader->ProcessCompleted();
|
|
if ( c > 0 )
|
|
{
|
|
RefreshBrowsers();
|
|
Con_Printf( "Thread loaded %i sounds\n", c );
|
|
}
|
|
}
|
|
|
|
void CWorkspaceManager::Frame( void )
|
|
{
|
|
static bool recursion_guard = false;
|
|
|
|
static double prev = 0.0;
|
|
double curr = (double) mx::getTickCount () / 1000.0;
|
|
double dt = ( curr - prev );
|
|
|
|
if ( recursion_guard )
|
|
return;
|
|
|
|
recursion_guard = true;
|
|
|
|
// clamp to MAX_FPS
|
|
if ( dt >= 0.0 && dt < MIN_TIMESTEP )
|
|
{
|
|
Sleep( max( 0, (int)( ( MIN_TIMESTEP - dt ) * 1000.0f ) ) );
|
|
|
|
recursion_guard = false;
|
|
return;
|
|
}
|
|
|
|
if ( prev != 0.0 )
|
|
{
|
|
dt = min( 0.1, dt );
|
|
|
|
Think( dt );
|
|
|
|
realtime += dt;
|
|
}
|
|
|
|
prev = curr;
|
|
|
|
recursion_guard = false;
|
|
}
|
|
|
|
int CWorkspaceManager::handleEvent( mxEvent *event )
|
|
{
|
|
int iret = 0;
|
|
switch ( event->event )
|
|
{
|
|
default:
|
|
break;
|
|
case mxEvent::Activate:
|
|
{
|
|
if (event->action)
|
|
{
|
|
mx::setIdleWindow( this );
|
|
// Force reload of localization data
|
|
OnChangeLanguage( GetLanguageId(), true );
|
|
}
|
|
else
|
|
{
|
|
mx::setIdleWindow( 0 );
|
|
}
|
|
iret = 1;
|
|
}
|
|
break;
|
|
case mxEvent::Idle:
|
|
{
|
|
iret = 1;
|
|
Frame();
|
|
}
|
|
break;
|
|
case mxEvent::KeyUp:
|
|
{
|
|
if ( event->key == VK_F5 )
|
|
{
|
|
RefreshBrowsers();
|
|
}
|
|
}
|
|
break;
|
|
case mxEvent::Action:
|
|
{
|
|
iret = 1;
|
|
switch ( event->action )
|
|
{
|
|
default:
|
|
{
|
|
if ( event->action >= IDC_WSM_FILE_RECENT_WORKSPACE_START &&
|
|
event->action < IDC_WSM_FILE_RECENT_WORKSPACE_END )
|
|
{
|
|
OnRecentWorkspace( event->action - IDC_WSM_FILE_RECENT_WORKSPACE_START );
|
|
}
|
|
else if ( event->action >= IDC_WSM_OPTIONS_LANGUAGESTART &&
|
|
event->action < IDC_WSM_OPTIONS_LANGUAGEEND )
|
|
{
|
|
OnChangeLanguage( event->action - IDC_WSM_OPTIONS_LANGUAGESTART );
|
|
}
|
|
else
|
|
{
|
|
iret = 0;
|
|
}
|
|
}
|
|
break;
|
|
case IDC_WSM_FILE_EXIT:
|
|
{
|
|
mx::quit();
|
|
}
|
|
break;
|
|
case IDC_WSM_FILE_WS_REFRESH:
|
|
{
|
|
RefreshBrowsers();
|
|
}
|
|
break;
|
|
case IDC_WSM_FILE_WS_NEW:
|
|
{
|
|
OnNewWorkspace();
|
|
}
|
|
break;
|
|
case IDC_WSM_FILE_WS_OPEN:
|
|
{
|
|
OnOpenWorkspace();
|
|
}
|
|
break;
|
|
case IDC_WSM_FILE_WS_CLOSE:
|
|
{
|
|
OnCloseWorkspace();
|
|
}
|
|
break;
|
|
case IDC_WSM_FILE_WS_SAVE:
|
|
{
|
|
OnSaveWorkspace();
|
|
}
|
|
break;
|
|
case IDC_WSM_FILE_WS_VSSPROPERTIES:
|
|
{
|
|
OnChangeVSSProperites();
|
|
}
|
|
break;
|
|
case IDC_WSM_FILE_WS_CHECKOUT:
|
|
{
|
|
OnCheckoutWorkspace();
|
|
}
|
|
break;
|
|
case IDC_WSM_FILE_WS_CHECKIN:
|
|
{
|
|
OnCheckinWorkspace();
|
|
}
|
|
break;
|
|
case IDC_WSM_PROJECT_PRJ_NEW:
|
|
{
|
|
OnNewProject();
|
|
}
|
|
break;
|
|
case IDC_WSM_PROJECT_PRJ_INSERT:
|
|
{
|
|
OnInsertProject();
|
|
}
|
|
break;
|
|
case IDC_WSM_PROJECT_PRJ_REMOVE:
|
|
{
|
|
OnRemoveProject();
|
|
}
|
|
break;
|
|
case IDC_WSM_PROJECT_PRJ_MODIFYCOMMENTS:
|
|
{
|
|
OnModifyProjectComments();
|
|
}
|
|
break;
|
|
case IDC_WSM_PROJECT_SCENE_NEW:
|
|
{
|
|
OnNewScene();
|
|
}
|
|
break;
|
|
case IDC_WSM_SOUNDENTRY_PLAY:
|
|
{
|
|
OnSoundPlay();
|
|
}
|
|
break;
|
|
case IDC_WSM_SOUNDENTRY_TOGGLEVOICEDUCK:
|
|
{
|
|
OnSoundToggleVoiceDuck();
|
|
}
|
|
break;
|
|
case IDC_WSM_SOUNDENTRY_EDITTEXT:
|
|
{
|
|
OnSoundEditText();
|
|
}
|
|
break;
|
|
case IDC_WSM_SOUNDENTRY_PROPERTIES:
|
|
{
|
|
OnSoundProperties();
|
|
}
|
|
break;
|
|
case IDC_WSM_SCENE_VCD_ADD:
|
|
{
|
|
OnSceneAddVCD();
|
|
}
|
|
break;
|
|
case IDC_WSM_SCENE_VCD_REMOVE:
|
|
{
|
|
OnSceneRemoveVCD();
|
|
}
|
|
break;
|
|
case IDC_WSM_SCENE_EDIT_COMMENTS:
|
|
{
|
|
OnModifySceneComments();
|
|
}
|
|
break;
|
|
case IDC_WSM_VCD_EDIT_COMMENTS:
|
|
{
|
|
OnModifyVCDComments();
|
|
}
|
|
break;
|
|
case IDC_WSM_SCENE_REMOVE:
|
|
{
|
|
OnRemoveScene();
|
|
}
|
|
break;
|
|
case IDC_WSM_SOUNDENTRY_SHOWINBROWSERS:
|
|
{
|
|
OnSoundShowInBrowsers();
|
|
}
|
|
break;
|
|
case IDC_WSM_SELECTION_CHECKOUT:
|
|
{
|
|
OnCheckout();
|
|
}
|
|
break;
|
|
case IDC_WSM_SELECTION_CHECKIN:
|
|
{
|
|
OnCheckin();
|
|
}
|
|
break;
|
|
case IDC_WSM_SELECTION_MOVEUP:
|
|
{
|
|
OnMoveUp();
|
|
}
|
|
break;
|
|
case IDC_WSM_SELECTION_MOVEDOWN:
|
|
{
|
|
OnMoveDown();
|
|
}
|
|
break;
|
|
case IDC_WSM_WAVEFILE_PROPERTIES:
|
|
{
|
|
OnWaveProperties();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case mxEvent::Size:
|
|
{
|
|
iret = 1;
|
|
PerformLayout( false );
|
|
}
|
|
break;
|
|
}
|
|
|
|
return iret;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CWorkspaceManager::PerformLayout( bool movebrowsers )
|
|
{
|
|
int width = w2();
|
|
int height = h2();
|
|
|
|
int statush = 100;
|
|
m_pWorkArea->setBounds( 0, 0, width, height - statush );
|
|
if ( movebrowsers )
|
|
{
|
|
GetBrowser()->setBounds( 0, 0, m_pWorkArea->w2(), m_pWorkArea->h2() / 3 );
|
|
if ( GetSoundBrowser() )
|
|
{
|
|
GetSoundBrowser()->setBounds( 0, m_pWorkArea->h2() / 3, m_pWorkArea->w2(), m_pWorkArea->h2() / 3 );
|
|
}
|
|
if ( GetWaveBrowser() )
|
|
{
|
|
GetWaveBrowser()->setBounds( 0, 2 * m_pWorkArea->h2() / 3, m_pWorkArea->w2(), m_pWorkArea->h2() / 3 );
|
|
}
|
|
}
|
|
|
|
g_pStatusWindow->setBounds( 0, height - statush, width, statush );
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Output : Returns true on success, false on failure.
|
|
//-----------------------------------------------------------------------------
|
|
bool CWorkspaceManager::CloseWorkspace()
|
|
{
|
|
CWorkspace *ws = GetBrowser()->GetWorkspace();
|
|
if ( !ws )
|
|
return true;
|
|
|
|
if ( !ws->CanClose() )
|
|
return false;
|
|
|
|
delete ws;
|
|
|
|
SetWorkspace( NULL );
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CWorkspaceManager::OnUpdateTitle( void )
|
|
{
|
|
CWorkspace *ws = GetBrowser()->GetWorkspace();
|
|
|
|
char szTitle[ 256 ];
|
|
if ( ws )
|
|
{
|
|
char const *fmt = g_appTitleFmt;
|
|
if ( ws->IsDirty() )
|
|
{
|
|
fmt = g_appTitleFmtModified;
|
|
}
|
|
Q_snprintf( szTitle, sizeof( szTitle ), fmt, ws->GetName(), CSentence::NameForLanguage( m_nLanguageId ) );
|
|
}
|
|
else
|
|
{
|
|
Q_snprintf( szTitle, sizeof( szTitle ), g_appTitle );
|
|
}
|
|
|
|
setLabel( szTitle );
|
|
|
|
UpdateMenus();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : *ws -
|
|
//-----------------------------------------------------------------------------
|
|
void CWorkspaceManager::SetWorkspace( CWorkspace *ws )
|
|
{
|
|
GetBrowser()->SetWorkspace( ws );
|
|
|
|
OnUpdateTitle();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CWorkspaceManager::OnNewWorkspace()
|
|
{
|
|
// Show file io
|
|
const char *fullpath = mxGetSaveFileName(
|
|
0,
|
|
".",
|
|
"*.vsw" );
|
|
|
|
if ( !fullpath || !fullpath[ 0 ] )
|
|
return;
|
|
|
|
// Strip game directory and slash
|
|
char workspace_name[ 512 ];
|
|
filesystem->FullPathToRelativePath( fullpath, workspace_name, sizeof( workspace_name ) );
|
|
|
|
Q_StripExtension( workspace_name, workspace_name, sizeof( workspace_name ) );
|
|
Q_DefaultExtension( workspace_name, ".vsw", sizeof( workspace_name ) );
|
|
|
|
if ( filesystem->FileExists( workspace_name ) )
|
|
{
|
|
Con_Printf( "%s exists already!\n", workspace_name );
|
|
Assert( 0 );
|
|
return;
|
|
}
|
|
|
|
LoadWorkspace( workspace_name );
|
|
}
|
|
|
|
void CWorkspaceManager::AddFileToRecentWorkspaceList( char const *filename )
|
|
{
|
|
int i;
|
|
int c = m_RecentFiles.Count();
|
|
|
|
for ( i = 0; i < c; i++ )
|
|
{
|
|
if (!Q_stricmp( m_RecentFiles[i].filename, filename ))
|
|
break;
|
|
}
|
|
|
|
// swap existing recent file
|
|
if ( i < c )
|
|
{
|
|
RecentFile rf = m_RecentFiles[0];
|
|
m_RecentFiles[ 0 ] = m_RecentFiles[ i ];
|
|
m_RecentFiles[ i ] = rf;
|
|
}
|
|
// insert recent file
|
|
else
|
|
{
|
|
RecentFile rf;
|
|
Q_strcpy( rf.filename, filename );
|
|
|
|
m_RecentFiles.AddToHead( rf );
|
|
}
|
|
|
|
while( m_RecentFiles.Count() > GetMaxRecentFiles() )
|
|
{
|
|
m_RecentFiles.Remove( m_RecentFiles.Count() - 1 );
|
|
}
|
|
|
|
UpdateRecentFilesMenu();
|
|
}
|
|
|
|
void CWorkspaceManager::LoadRecentFilesMenuFromDisk()
|
|
{
|
|
KeyValues *kv = new KeyValues( "recentfiles" );
|
|
if ( kv->LoadFromFile( filesystem, RECENT_FILES_FILE ) )
|
|
{
|
|
for ( KeyValues *sub = kv->GetFirstSubKey(); sub; sub = sub->GetNextKey() )
|
|
{
|
|
RecentFile rf;
|
|
Q_strncpy( rf.filename, sub->GetString(), sizeof( rf ) );
|
|
m_RecentFiles.AddToTail( rf );
|
|
}
|
|
}
|
|
kv->deleteThis();
|
|
|
|
UpdateRecentFilesMenu();
|
|
}
|
|
|
|
void CWorkspaceManager::AutoLoad( char const *workspace )
|
|
{
|
|
if ( workspace )
|
|
{
|
|
LoadWorkspace( workspace );
|
|
}
|
|
else
|
|
{
|
|
if ( m_RecentFiles.Count() > 0 )
|
|
{
|
|
LoadWorkspace( m_RecentFiles[ 0 ].filename );
|
|
}
|
|
}
|
|
}
|
|
|
|
void CWorkspaceManager::SaveRecentFilesMenuToDisk()
|
|
{
|
|
int i;
|
|
int c = m_RecentFiles.Count();
|
|
|
|
CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
|
|
|
|
buf.Printf( "recentfiles\n{\n" );
|
|
|
|
for ( i = 0; i < c; i++ )
|
|
{
|
|
buf.Printf( "\t\"%i\"\t\"%s\"\n", i + 1, m_RecentFiles[ i ].filename );
|
|
}
|
|
|
|
buf.Printf( "}\n" );
|
|
|
|
char const *recentfiles = RECENT_FILES_FILE;
|
|
|
|
// Write it out baby
|
|
FileHandle_t fh = filesystem->Open( recentfiles, "wt" );
|
|
if (fh)
|
|
{
|
|
filesystem->Write( buf.Base(), buf.TellPut(), fh );
|
|
filesystem->Close(fh);
|
|
}
|
|
else
|
|
{
|
|
Con_Printf( "CWorkspace::SaveRecentFilesMenuToDisk: Unable to write file %s!!!\n", recentfiles );
|
|
}
|
|
}
|
|
|
|
void CWorkspaceManager::UpdateRecentFilesMenu()
|
|
{
|
|
int c = m_RecentFiles.Count();
|
|
|
|
while ( c > m_nRecentMenuItems )
|
|
{
|
|
m_pRecentFileMenu->add( "(empty)", IDC_WSM_FILE_RECENT_WORKSPACE_START + m_nRecentMenuItems++ );
|
|
}
|
|
|
|
for (int i = 0; i < c; i++)
|
|
{
|
|
m_pMenuBar->modify (IDC_WSM_FILE_RECENT_WORKSPACE_START + i, IDC_WSM_FILE_RECENT_WORKSPACE_START + i, m_RecentFiles[i].filename );
|
|
}
|
|
}
|
|
|
|
void CWorkspaceManager::LoadWorkspace( char const *filename )
|
|
{
|
|
if ( !CloseWorkspace() )
|
|
return;
|
|
|
|
Con_Printf( "Loading workspace %s\n", filename );
|
|
|
|
CWorkspace *wks = new CWorkspace( filename );
|
|
SetWorkspace( wks );
|
|
|
|
AddFileToRecentWorkspaceList( filename );
|
|
|
|
OnUpdateTitle();
|
|
|
|
UpdateMenus();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CWorkspaceManager::OnOpenWorkspace()
|
|
{
|
|
// Show file io
|
|
const char *fullpath = mxGetOpenFileName(
|
|
0,
|
|
".",
|
|
"*.vsw" );
|
|
|
|
if ( !fullpath || !fullpath[ 0 ] )
|
|
return;
|
|
|
|
// Strip game directory and slash
|
|
char workspace_name[ 512 ];
|
|
filesystem->FullPathToRelativePath( fullpath, workspace_name, sizeof( workspace_name ) );
|
|
|
|
LoadWorkspace( workspace_name );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CWorkspaceManager::OnCloseWorkspace()
|
|
{
|
|
if ( !CloseWorkspace() )
|
|
return;
|
|
|
|
Con_Printf( "Closed workspace\n" );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CWorkspaceManager::OnSaveWorkspace()
|
|
{
|
|
CWorkspace *ws = GetBrowser()->GetWorkspace();
|
|
if ( ws )
|
|
{
|
|
ws->SaveChanges();
|
|
|
|
OnUpdateTitle();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CWorkspaceManager::OnNewProject()
|
|
{
|
|
Con_Printf( "OnNewProject()\n" );
|
|
|
|
// Show file io
|
|
const char *fullpath = mxGetSaveFileName(
|
|
0,
|
|
".",
|
|
"*.vsp" );
|
|
|
|
if ( !fullpath || !fullpath[ 0 ] )
|
|
return;
|
|
|
|
// Strip game directory and slash
|
|
char project_name[ 512 ];
|
|
filesystem->FullPathToRelativePath( fullpath, project_name, sizeof( project_name ) );
|
|
|
|
Q_StripExtension( project_name, project_name, sizeof( project_name ) );
|
|
Q_DefaultExtension( project_name, ".vsp", sizeof( project_name ) );
|
|
|
|
if ( filesystem->FileExists( project_name ) )
|
|
{
|
|
Con_Printf( "%s exists already!\n", project_name );
|
|
Assert( 0 );
|
|
return;
|
|
}
|
|
|
|
CWorkspace *ws = GetBrowser()->GetWorkspace();
|
|
if ( !ws )
|
|
{
|
|
// Create one on the fly
|
|
char workspace_name[ 512 ];
|
|
Q_StripExtension( project_name, workspace_name, sizeof( workspace_name ) );
|
|
Q_DefaultExtension( workspace_name, ".vsw", sizeof( workspace_name ) );
|
|
|
|
if ( !filesystem->FileExists( workspace_name ) )
|
|
{
|
|
int retval = mxMessageBox( NULL, va( "Automatically create workspace %s?", workspace_name ), g_appTitle, MX_MB_YESNOCANCEL );
|
|
if ( retval != 0 )
|
|
{
|
|
Con_Printf( "Canceling project creation\n" );
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Con_Printf( "Found workspace '%s', automatically loading...\n", workspace_name );
|
|
}
|
|
|
|
LoadWorkspace( workspace_name );
|
|
|
|
ws = GetBrowser()->GetWorkspace();
|
|
}
|
|
|
|
if ( ws && ws->FindProjectFile( project_name ) )
|
|
{
|
|
Con_Printf( "Project %s already exists in workspace\n", project_name );
|
|
return;
|
|
}
|
|
|
|
// Create a new project and add it into current workspace
|
|
CProject *proj = new CProject( ws, project_name );
|
|
Assert( proj );
|
|
Assert( ws );
|
|
|
|
if ( ws )
|
|
{
|
|
GetBrowser()->AddProject( proj );
|
|
}
|
|
|
|
OnUpdateTitle();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CWorkspaceManager::OnInsertProject()
|
|
{
|
|
Con_Printf( "OnInsertProject()\n" );
|
|
|
|
// Show file io
|
|
const char *fullpath = mxGetOpenFileName(
|
|
0,
|
|
".",
|
|
"*.vsp" );
|
|
|
|
if ( !fullpath || !fullpath[ 0 ] )
|
|
return;
|
|
|
|
// Strip game directory and slash
|
|
char project_name[ 512 ];
|
|
filesystem->FullPathToRelativePath( fullpath, project_name, sizeof( project_name ) );
|
|
|
|
Q_StripExtension( project_name, project_name, sizeof( project_name ) );
|
|
Q_DefaultExtension( project_name, ".vsp", sizeof( project_name ) );
|
|
|
|
CWorkspace *ws = GetBrowser()->GetWorkspace();
|
|
if ( !ws )
|
|
{
|
|
// Create one on the fly
|
|
char workspace_name[ 512 ];
|
|
Q_StripExtension( project_name, workspace_name, sizeof( workspace_name ) );
|
|
Q_DefaultExtension( workspace_name, ".vsw", sizeof( workspace_name ) );
|
|
|
|
if ( !filesystem->FileExists( workspace_name ) )
|
|
{
|
|
int retval = mxMessageBox( NULL, va( "Automatically create workspace %s?", workspace_name ), g_appTitle, MX_MB_YESNOCANCEL );
|
|
if ( retval != 0 )
|
|
{
|
|
Con_Printf( "Canceling project creation\n" );
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Con_Printf( "Found workspace '%s', automatically loading...\n", workspace_name );
|
|
}
|
|
|
|
LoadWorkspace( workspace_name );
|
|
|
|
ws = GetBrowser()->GetWorkspace();
|
|
}
|
|
|
|
if ( ws && ws->FindProjectFile( project_name ) )
|
|
{
|
|
Con_Printf( "Project %s already exists in workspace\n", project_name );
|
|
return;
|
|
}
|
|
|
|
// Create a new project and add it into current workspace
|
|
CProject *proj = new CProject( ws, project_name );
|
|
Assert( proj );
|
|
Assert( ws );
|
|
|
|
if ( ws )
|
|
{
|
|
GetBrowser()->AddProject( proj );
|
|
}
|
|
|
|
OnUpdateTitle();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CWorkspaceManager::OnRemoveProject()
|
|
{
|
|
Con_Printf( "OnRemoveProject()\n" );
|
|
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( !item )
|
|
return;
|
|
|
|
CProject *project = item->GetProject();
|
|
if ( !project )
|
|
{
|
|
Con_Printf( "Can't remove project, item is not a project\n" );
|
|
return;
|
|
}
|
|
|
|
CWorkspace *ws = GetBrowser()->GetWorkspace();
|
|
if ( !ws )
|
|
{
|
|
Con_Printf( "Can't remove project '%s', no current workspace?!\n",
|
|
project->GetName() );
|
|
return;
|
|
}
|
|
|
|
ws->RemoveProject( project );
|
|
Con_Printf( "Removed project '%s'\n", project->GetName() );
|
|
delete project;
|
|
|
|
GetBrowser()->PopulateTree();
|
|
|
|
OnUpdateTitle();
|
|
}
|
|
|
|
void CWorkspaceManager::OnRemoveScene()
|
|
{
|
|
Con_Printf( "OnRemoveScene()\n" );
|
|
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( !item )
|
|
return;
|
|
|
|
CScene *scene = item->GetScene();
|
|
if ( !scene )
|
|
{
|
|
Con_Printf( "Can't remove scene, item is not a scene\n" );
|
|
return;
|
|
}
|
|
|
|
CProject *project = scene->GetOwnerProject();
|
|
if ( !project )
|
|
{
|
|
Con_Printf( "Can't remove scene '%s', no current owner project?!\n",
|
|
scene->GetName() );
|
|
return;
|
|
}
|
|
|
|
project->RemoveScene( scene );
|
|
Con_Printf( "Removed scene '%s'\n", scene->GetName() );
|
|
delete scene;
|
|
|
|
GetBrowser()->PopulateTree();
|
|
|
|
OnUpdateTitle();
|
|
}
|
|
|
|
void CWorkspaceManager::OnNewScene()
|
|
{
|
|
Con_Printf( "OnNewScene()\n" );
|
|
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( !item )
|
|
return;
|
|
|
|
CProject *project = item->GetProject();
|
|
if ( !project )
|
|
{
|
|
Con_Printf( "Can't add new scene, selected item is not a project\n" );
|
|
return;
|
|
}
|
|
|
|
CInputParams params;
|
|
memset( ¶ms, 0, sizeof( params ) );
|
|
Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Create scene in '%s'", project->GetName() );
|
|
Q_strcpy( params.m_szPrompt, "Scene Name:" );
|
|
Q_strcpy( params.m_szInputText, "" );
|
|
|
|
if ( !InputProperties( ¶ms ) )
|
|
return;
|
|
|
|
if ( !params.m_szInputText[ 0 ] )
|
|
{
|
|
Con_Printf( "You must name the scene!\n" );
|
|
return;
|
|
}
|
|
|
|
CScene *scene = new CScene( project, params.m_szInputText );
|
|
Assert( scene );
|
|
|
|
project->AddScene( scene );
|
|
|
|
Con_Printf( "Added scene '%s' to project '%s'\n", scene->GetName(),
|
|
project->GetName() );
|
|
|
|
GetBrowser()->PopulateTree();
|
|
|
|
OnUpdateTitle();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CWorkspaceManager::OnModifyProjectComments()
|
|
{
|
|
Con_Printf( "OnModifyProjectComments()\n" );
|
|
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( !item )
|
|
return;
|
|
|
|
CProject *project = item->GetProject();
|
|
if ( !project )
|
|
{
|
|
Con_Printf( "Can't modify comments, item is not a project\n" );
|
|
return;
|
|
}
|
|
|
|
CInputParams params;
|
|
memset( ¶ms, 0, sizeof( params ) );
|
|
Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Edit comments for '%s'", project->GetName() );
|
|
Q_strcpy( params.m_szPrompt, "Comments:" );
|
|
Q_strncpy( params.m_szInputText, project->GetComments(), sizeof( params.m_szInputText ) );
|
|
|
|
if ( !InputProperties( ¶ms ) )
|
|
return;
|
|
|
|
if ( !Q_strcmp( params.m_szInputText, project->GetComments() ) )
|
|
return;
|
|
|
|
project->SetComments( params.m_szInputText );
|
|
|
|
GetBrowser()->PopulateTree();
|
|
|
|
OnUpdateTitle();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : index -
|
|
//-----------------------------------------------------------------------------
|
|
void CWorkspaceManager::OnRecentWorkspace( int index )
|
|
{
|
|
if ( index < 0 || index >= m_RecentFiles.Count() )
|
|
return;
|
|
|
|
LoadWorkspace( m_RecentFiles[ index ].filename );
|
|
}
|
|
|
|
int CWorkspaceManager::GetLanguageId() const
|
|
{
|
|
return m_nLanguageId;
|
|
}
|
|
|
|
void CWorkspaceManager::OnChangeLanguage( int lang_index, bool force /* = false */ )
|
|
{
|
|
bool changed = m_nLanguageId != lang_index;
|
|
m_nLanguageId = lang_index;
|
|
|
|
if ( changed || force )
|
|
{
|
|
// Update the menu
|
|
for ( int i = 0; i < CC_NUM_LANGUAGES; i++ )
|
|
{
|
|
int id = IDC_WSM_OPTIONS_LANGUAGESTART + i;
|
|
m_pMenuCloseCaptionLanguages->setChecked( id, i == m_nLanguageId );
|
|
}
|
|
|
|
bool filechanged = false;
|
|
|
|
char const *suffix = CSentence::NameForLanguage( lang_index );
|
|
if ( Q_stricmp( suffix, "unknown_language" ) )
|
|
{
|
|
char fn[ MAX_PATH ];
|
|
Q_snprintf( fn, sizeof( fn ), "resource/closecaption_%s.txt", suffix );
|
|
|
|
long filetimestamp = filesystem->GetFileTime( fn );
|
|
|
|
|
|
if ( filesystem->FileExists( fn ) )
|
|
{
|
|
if ( m_lEnglishCaptionsFileChangeTime != filetimestamp )
|
|
{
|
|
filechanged = true;
|
|
m_lEnglishCaptionsFileChangeTime = filetimestamp;
|
|
//Con_Printf( "Reloading close caption data from '%s'\n", fn );
|
|
g_pVGuiLocalize->RemoveAll();
|
|
g_pVGuiLocalize->AddFile( fn );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Con_Printf( "CWorkspaceManager::OnChangeLanguage Warning, can't find localization file %s\n", fn );
|
|
}
|
|
}
|
|
|
|
if ( !force || filechanged )
|
|
{
|
|
// Update all text for items.
|
|
RefreshBrowsers();
|
|
|
|
OnUpdateTitle();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CWorkspaceManager::OnDoubleClicked( ITreeItem *item )
|
|
{
|
|
CSoundEntry *s = item->GetSoundEntry();
|
|
if ( s )
|
|
{
|
|
s->Play();
|
|
return;
|
|
}
|
|
}
|
|
|
|
void CWorkspaceManager::OnSoundPlay()
|
|
{
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( item->GetSoundEntry() )
|
|
{
|
|
item->GetSoundEntry()->Play();
|
|
}
|
|
else if ( item->GetWaveFile() )
|
|
{
|
|
item->GetWaveFile()->Play();
|
|
}
|
|
}
|
|
|
|
void CWorkspaceManager::OnSoundToggleVoiceDuck()
|
|
{
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( item->GetWaveFile() )
|
|
{
|
|
item->GetWaveFile()->ToggleVoiceDucking();
|
|
}
|
|
}
|
|
|
|
void CWorkspaceManager::OnSoundEditText()
|
|
{
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( !item )
|
|
return;
|
|
|
|
CWaveFile *s = item->GetWaveFile();
|
|
if ( !s )
|
|
return;
|
|
|
|
CInputParams params;
|
|
memset( ¶ms, 0, sizeof( params ) );
|
|
Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Edit text of '%s'", s->GetName() );
|
|
Q_strcpy( params.m_szPrompt, "Sentence text:" );
|
|
V_strcpy_safe( params.m_szInputText, s->GetSentenceText() );
|
|
|
|
if ( !InputProperties( ¶ms ) )
|
|
return;
|
|
|
|
if ( !Q_stricmp( params.m_szInputText, s->GetSentenceText() ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
s->SetSentenceText( params.m_szInputText );
|
|
|
|
GetBrowser()->PopulateTree();
|
|
|
|
OnUpdateTitle();
|
|
}
|
|
|
|
// Scene entries
|
|
void CWorkspaceManager::OnSceneAddVCD()
|
|
{
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( !item )
|
|
return;
|
|
|
|
CScene *scene = item->GetScene();
|
|
if ( !scene )
|
|
return;
|
|
|
|
// Show file io
|
|
const char *fullpath = mxGetOpenFileName(
|
|
0,
|
|
".",
|
|
"*.vcd" );
|
|
|
|
if ( !fullpath || !fullpath[ 0 ] )
|
|
return;
|
|
|
|
// Strip game directory and slash
|
|
char vcd_name[ 512 ];
|
|
filesystem->FullPathToRelativePath( fullpath, vcd_name, sizeof( vcd_name ) );
|
|
|
|
Q_StripExtension( vcd_name, vcd_name, sizeof( vcd_name ) );
|
|
Q_DefaultExtension( vcd_name, ".vcd", sizeof( vcd_name ) );
|
|
|
|
if ( scene->FindVCD( vcd_name ) )
|
|
{
|
|
Con_Printf( "File '%s' is already in scene '%s'\n", vcd_name, scene->GetName() );
|
|
return;
|
|
}
|
|
|
|
CVCDFile *vcd = new CVCDFile( scene, vcd_name );
|
|
|
|
scene->AddVCD( vcd );
|
|
|
|
GetBrowser()->PopulateTree();
|
|
|
|
OnUpdateTitle();
|
|
}
|
|
|
|
void CWorkspaceManager::OnModifySceneComments()
|
|
{
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( !item )
|
|
return;
|
|
|
|
CScene *scene = item->GetScene();
|
|
if ( !scene )
|
|
return;
|
|
|
|
CInputParams params;
|
|
memset( ¶ms, 0, sizeof( params ) );
|
|
Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Edit comments for '%s'", scene->GetName() );
|
|
Q_strcpy( params.m_szPrompt, "Comments:" );
|
|
Q_strncpy( params.m_szInputText, scene->GetComments(), sizeof( params.m_szInputText ) );
|
|
|
|
if ( !InputProperties( ¶ms ) )
|
|
return;
|
|
|
|
if ( !Q_strcmp( params.m_szInputText, scene->GetComments() ) )
|
|
return;
|
|
|
|
scene->SetComments( params.m_szInputText );
|
|
|
|
GetBrowser()->PopulateTree();
|
|
|
|
OnUpdateTitle();
|
|
}
|
|
|
|
void CWorkspaceManager::OnModifyVCDComments()
|
|
{
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( !item )
|
|
return;
|
|
|
|
CVCDFile *file = item->GetVCDFile();
|
|
if ( !file )
|
|
return;
|
|
|
|
CInputParams params;
|
|
memset( ¶ms, 0, sizeof( params ) );
|
|
Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Edit comments for '%s'", file->GetName() );
|
|
Q_strcpy( params.m_szPrompt, "Comments:" );
|
|
Q_strncpy( params.m_szInputText, file->GetComments(), sizeof( params.m_szInputText ) );
|
|
|
|
if ( !InputProperties( ¶ms ) )
|
|
return;
|
|
|
|
if ( !Q_strcmp( params.m_szInputText, file->GetComments() ) )
|
|
return;
|
|
|
|
file->SetComments( params.m_szInputText );
|
|
|
|
GetBrowser()->PopulateTree();
|
|
|
|
OnUpdateTitle();
|
|
}
|
|
|
|
void CWorkspaceManager::OnSceneRemoveVCD()
|
|
{
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( !item )
|
|
return;
|
|
|
|
CVCDFile *file = item->GetVCDFile();
|
|
if ( !file )
|
|
return;
|
|
|
|
CScene *scene = file->GetOwnerScene();
|
|
if ( !scene )
|
|
return;
|
|
|
|
scene->RemoveVCD( file );
|
|
|
|
GetBrowser()->PopulateTree();
|
|
|
|
OnUpdateTitle();
|
|
}
|
|
|
|
void CWorkspaceManager::ShowContextMenu( int x, int y, ITreeItem *p )
|
|
{
|
|
CWorkspace *w = p->GetWorkspace();
|
|
if ( w )
|
|
{
|
|
ShowContextMenu_Workspace( x, y, w );
|
|
return;
|
|
}
|
|
|
|
CProject *proj = p->GetProject();
|
|
if ( proj )
|
|
{
|
|
ShowContextMenu_Project( x, y, proj );
|
|
return;
|
|
}
|
|
|
|
CScene *scene = p->GetScene();
|
|
if ( scene )
|
|
{
|
|
ShowContextMenu_Scene( x, y, scene );
|
|
return;
|
|
}
|
|
|
|
CVCDFile *vcd = p->GetVCDFile();
|
|
if ( vcd )
|
|
{
|
|
ShowContextMenu_VCD( x, y, vcd );
|
|
return;
|
|
}
|
|
|
|
CSoundEntry *sound = p->GetSoundEntry();
|
|
if ( sound )
|
|
{
|
|
ShowContextMenu_SoundEntry( x, y, sound );
|
|
return;
|
|
}
|
|
|
|
CWaveFile *wave = p->GetWaveFile();
|
|
if ( wave )
|
|
{
|
|
ShowContextMenu_WaveFile( x, y, wave );
|
|
return;
|
|
}
|
|
|
|
Con_Printf( "unknown tree item type\n" );
|
|
Assert( 0 );
|
|
}
|
|
|
|
void CWorkspaceManager::ShowContextMenu_Workspace( int x, int y, CWorkspace *ws )
|
|
{
|
|
if ( !ws )
|
|
return;
|
|
|
|
// New project and insert project
|
|
mxPopupMenu *pop = new mxPopupMenu();
|
|
|
|
pop->add ("Create New Project...", IDC_WSM_PROJECT_PRJ_NEW );
|
|
pop->add ("Insert Project...", IDC_WSM_PROJECT_PRJ_INSERT );
|
|
pop->addSeparator();
|
|
pop->add( "VSS Properties...", IDC_WSM_FILE_WS_VSSPROPERTIES );
|
|
|
|
if ( !filesystem->IsFileWritable( ws->GetFileName() ) )
|
|
{
|
|
pop->add( va( "Checkout '%s'", ws->GetName() ), IDC_WSM_SELECTION_CHECKOUT );
|
|
}
|
|
else
|
|
{
|
|
pop->add( va( "Checkin '%s'", ws->GetName() ), IDC_WSM_SELECTION_CHECKIN );
|
|
}
|
|
|
|
pop->popup( this, x, y );
|
|
}
|
|
|
|
void CWorkspaceManager::ShowContextMenu_Project( int x, int y, CProject *project )
|
|
{
|
|
// New scene, edit comments
|
|
mxPopupMenu *pop = new mxPopupMenu();
|
|
|
|
pop->add ("Create New Scene...", IDC_WSM_PROJECT_SCENE_NEW );
|
|
pop->addSeparator();
|
|
pop->add ("Remove Project...", IDC_WSM_PROJECT_PRJ_REMOVE );
|
|
pop->addSeparator();
|
|
pop->add( "Edit comments...", IDC_WSM_PROJECT_PRJ_MODIFYCOMMENTS );
|
|
if ( !project->IsFirstChild() || !project->IsLastChild() )
|
|
{
|
|
pop->addSeparator();
|
|
if( !project->IsFirstChild() )
|
|
{
|
|
pop->add( va( "Move '%s' Up", project->GetName() ), IDC_WSM_SELECTION_MOVEUP );
|
|
}
|
|
if( !project->IsLastChild() )
|
|
{
|
|
pop->add( va( "Move '%s' Down", project->GetName() ), IDC_WSM_SELECTION_MOVEDOWN );
|
|
}
|
|
}
|
|
pop->addSeparator();
|
|
|
|
if ( !filesystem->IsFileWritable( project->GetFileName() ) )
|
|
{
|
|
pop->add( va( "Checkout '%s'", project->GetName() ), IDC_WSM_SELECTION_CHECKOUT );
|
|
}
|
|
else
|
|
{
|
|
pop->add( va( "Checkin '%s'", project->GetName() ), IDC_WSM_SELECTION_CHECKIN );
|
|
}
|
|
|
|
pop->popup( this, x, y );
|
|
}
|
|
|
|
void CWorkspaceManager::ShowContextMenu_Scene( int x, int y, CScene *scene )
|
|
{
|
|
// New scene, edit comments
|
|
mxPopupMenu *pop = new mxPopupMenu();
|
|
|
|
pop->add( va( "Add VCD to '%s'...", scene->GetName() ), IDC_WSM_SCENE_VCD_ADD );
|
|
pop->addSeparator();
|
|
pop->add ("Remove Scene", IDC_WSM_SCENE_REMOVE );
|
|
pop->addSeparator();
|
|
pop->add( va( "Edit comments..." ), IDC_WSM_SCENE_EDIT_COMMENTS );
|
|
if ( !scene->IsFirstChild() || !scene->IsLastChild() )
|
|
{
|
|
pop->addSeparator();
|
|
if( !scene->IsFirstChild() )
|
|
{
|
|
pop->add( va( "Move '%s' Up", scene->GetName() ), IDC_WSM_SELECTION_MOVEUP );
|
|
}
|
|
if( !scene->IsLastChild() )
|
|
{
|
|
pop->add( va( "Move '%s' Down", scene->GetName() ), IDC_WSM_SELECTION_MOVEDOWN );
|
|
}
|
|
}
|
|
|
|
pop->popup( this, x, y );
|
|
}
|
|
|
|
void CWorkspaceManager::ShowContextMenu_VCD( int x, int y, CVCDFile *vcd )
|
|
{
|
|
// New scene, edit comments
|
|
mxPopupMenu *pop = new mxPopupMenu();
|
|
|
|
pop->add( va( "Remove VCD" ), IDC_WSM_SCENE_VCD_REMOVE );
|
|
pop->addSeparator();
|
|
pop->add( va( "Edit comments..." ), IDC_WSM_VCD_EDIT_COMMENTS );
|
|
if ( !vcd->IsFirstChild() || !vcd->IsLastChild() )
|
|
{
|
|
pop->addSeparator();
|
|
if( !vcd->IsFirstChild() )
|
|
{
|
|
pop->add( va( "Move '%s' Up", vcd->GetName() ), IDC_WSM_SELECTION_MOVEUP );
|
|
}
|
|
if( !vcd->IsLastChild() )
|
|
{
|
|
pop->add( va( "Move '%s' Down", vcd->GetName() ), IDC_WSM_SELECTION_MOVEDOWN );
|
|
}
|
|
}
|
|
pop->addSeparator();
|
|
if ( !filesystem->IsFileWritable( vcd->GetName() ) )
|
|
{
|
|
pop->add( va( "Checkout '%s'", vcd->GetName() ), IDC_WSM_SELECTION_CHECKOUT );
|
|
}
|
|
else
|
|
{
|
|
pop->add( va( "Checkin '%s'", vcd->GetName() ), IDC_WSM_SELECTION_CHECKIN );
|
|
}
|
|
|
|
pop->popup( this, x, y );
|
|
}
|
|
|
|
void CWorkspaceManager::ShowContextMenu_SoundEntry( int x, int y, CSoundEntry *entry )
|
|
{
|
|
// New scene, edit comments
|
|
mxPopupMenu *pop = new mxPopupMenu();
|
|
|
|
pop->add ("&Play", IDC_WSM_SOUNDENTRY_PLAY );
|
|
// pop->add( "&Jump To", IDC_WSM_SOUNDENTRY_SHOWINBROWSERS );
|
|
pop->addSeparator();
|
|
|
|
pop->add( "Properties...", IDC_WSM_SOUNDENTRY_PROPERTIES );
|
|
|
|
pop->popup( this, x, y );
|
|
}
|
|
|
|
void CWorkspaceManager::ShowContextMenu_WaveFile( int x, int y, CWaveFile *entry )
|
|
{
|
|
// New scene, edit comments
|
|
mxPopupMenu *pop = new mxPopupMenu();
|
|
|
|
pop->add ("&Play", IDC_WSM_SOUNDENTRY_PLAY );
|
|
// pop->add( "&Jump To", IDC_WSM_SOUNDENTRY_SHOWINBROWSERS );
|
|
|
|
if ( entry->GetVoiceDuck() )
|
|
{
|
|
pop->add ("Disable &voice duck", IDC_WSM_SOUNDENTRY_TOGGLEVOICEDUCK );
|
|
}
|
|
else
|
|
{
|
|
pop->add ("Enable &voice duck", IDC_WSM_SOUNDENTRY_TOGGLEVOICEDUCK );
|
|
}
|
|
pop->add( "&Edit sentence text...", IDC_WSM_SOUNDENTRY_EDITTEXT );
|
|
pop->addSeparator();
|
|
if ( !filesystem->IsFileWritable( entry->GetFileName() ) )
|
|
{
|
|
pop->add( va( "Checkout '%s'", entry->GetName() ), IDC_WSM_SELECTION_CHECKOUT );
|
|
}
|
|
else
|
|
{
|
|
pop->add( va( "Checkin '%s'", entry->GetName() ), IDC_WSM_SELECTION_CHECKIN );
|
|
}
|
|
pop->addSeparator();
|
|
pop->add( "Properties...", IDC_WSM_WAVEFILE_PROPERTIES );
|
|
|
|
pop->popup( this, x, y );
|
|
}
|
|
|
|
|
|
void CWorkspaceManager::OnChangeVSSProperites()
|
|
{
|
|
CWorkspace *ws = GetBrowser()->GetWorkspace();
|
|
if ( !ws )
|
|
{
|
|
return;
|
|
}
|
|
|
|
CVSSParams params;
|
|
memset( ¶ms, 0, sizeof( params ) );
|
|
Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "VSS Properites" );
|
|
V_strcpy_safe( params.m_szUserName, ws->GetVSSUserName() );
|
|
V_strcpy_safe( params.m_szProject, ws->GetVSSProject() );
|
|
|
|
if ( !VSSProperties( ¶ms ) )
|
|
return;
|
|
|
|
if ( !params.m_szUserName[ 0 ] )
|
|
{
|
|
Con_Printf( "You must enter a user name\n" );
|
|
return;
|
|
}
|
|
|
|
if ( !params.m_szProject[ 0 ] )
|
|
{
|
|
Con_Printf( "You must enter a project name\n" );
|
|
return;
|
|
}
|
|
|
|
ws->SetVSSUserName( params.m_szUserName );
|
|
ws->SetVSSProject( params.m_szProject );
|
|
|
|
ws->SetDirty( true );
|
|
|
|
Con_Printf( "VSS user = '%s', project = '%s'\n",
|
|
ws->GetVSSUserName(), ws->GetVSSProject() );
|
|
}
|
|
|
|
void CWorkspaceManager::OnCheckoutWorkspace()
|
|
{
|
|
CWorkspace *ws = GetBrowser()->GetWorkspace();
|
|
if ( !ws )
|
|
{
|
|
return;
|
|
}
|
|
|
|
ws->Checkout();
|
|
}
|
|
|
|
void CWorkspaceManager::OnCheckinWorkspace()
|
|
{
|
|
CWorkspace *ws = GetBrowser()->GetWorkspace();
|
|
if ( !ws )
|
|
{
|
|
return;
|
|
}
|
|
|
|
ws->Checkin();
|
|
}
|
|
|
|
|
|
#define CX_ICON 16
|
|
#define CY_ICON 16
|
|
|
|
HIMAGELIST CWorkspaceManager::CreateImageList()
|
|
{
|
|
HIMAGELIST list;
|
|
|
|
list = ImageList_Create( CX_ICON, CY_ICON,
|
|
FALSE, NUM_IMAGES, 0 );
|
|
|
|
// Load the icon resources, and add the icons to the image list.
|
|
HICON hicon;
|
|
int slot;
|
|
#if defined( DBGFLAG_ASSERT )
|
|
int c = 0;
|
|
#endif
|
|
|
|
hicon = LoadIcon( GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_WORKSPACE));
|
|
slot = ImageList_AddIcon(list, hicon);
|
|
Assert( slot == c++ );
|
|
DeleteObject( hicon );
|
|
|
|
hicon = LoadIcon( GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_WORKSPACE_CHECKEDOUT));
|
|
slot = ImageList_AddIcon(list, hicon);
|
|
Assert( slot == c++ );
|
|
DeleteObject( hicon );
|
|
|
|
hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_PROJECT));
|
|
slot = ImageList_AddIcon(list, hicon);
|
|
Assert( slot == c++ );
|
|
DeleteObject( hicon );
|
|
|
|
hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_PROJECT_CHECKEDOUT));
|
|
slot = ImageList_AddIcon(list, hicon);
|
|
Assert( slot == c++ );
|
|
DeleteObject( hicon );
|
|
|
|
hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_SCENE));
|
|
slot = ImageList_AddIcon(list, hicon);
|
|
Assert( slot == c++ );
|
|
DeleteObject( hicon );
|
|
|
|
// hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_SCENE_CHECKEDOUT));
|
|
// slot = ImageList_AddIcon(list, hicon);
|
|
// Assert( slot == c++ );
|
|
// DeleteObject( hicon );
|
|
|
|
hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_VCD));
|
|
slot = ImageList_AddIcon(list, hicon);
|
|
Assert( slot == c++ );
|
|
DeleteObject( hicon );
|
|
|
|
hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_VCD_CHECKEDOUT ));
|
|
slot = ImageList_AddIcon(list, hicon);
|
|
Assert( slot == c++ );
|
|
DeleteObject( hicon );
|
|
|
|
hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_WAV));
|
|
slot = ImageList_AddIcon(list, hicon);
|
|
Assert( slot == c++ );
|
|
DeleteObject( hicon );
|
|
|
|
hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_WAV_CHECKEDOUT));
|
|
slot = ImageList_AddIcon(list, hicon);
|
|
Assert( slot == c++ );
|
|
DeleteObject( hicon );
|
|
|
|
hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_SPEAK));
|
|
slot = ImageList_AddIcon(list, hicon);
|
|
Assert( slot == c++ );
|
|
DeleteObject( hicon );
|
|
|
|
hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_SPEAK_CHECKEDOUT));
|
|
slot = ImageList_AddIcon(list, hicon);
|
|
Assert( slot == c++ );
|
|
DeleteObject( hicon );
|
|
|
|
return list;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CWorkspaceManager::RefreshBrowsers()
|
|
{
|
|
if ( GetBrowser() )
|
|
{
|
|
GetBrowser()->PopulateTree();
|
|
}
|
|
|
|
if ( GetSoundBrowser() )
|
|
{
|
|
GetSoundBrowser()->RepopulateTree();
|
|
}
|
|
|
|
if ( GetWaveBrowser() )
|
|
{
|
|
GetWaveBrowser()->RepopulateTree();
|
|
}
|
|
}
|
|
|
|
void CWorkspaceManager::OnSoundShowInBrowsers()
|
|
{
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( !item )
|
|
return;
|
|
|
|
CSoundEntry *se = item->GetSoundEntry();
|
|
if ( se )
|
|
{
|
|
GetSoundBrowser()->JumpToItem( se );
|
|
return;
|
|
}
|
|
|
|
CWaveFile *wave = item->GetWaveFile();
|
|
if ( wave )
|
|
{
|
|
GetWaveBrowser()->JumpToItem( wave );
|
|
if ( wave->GetOwnerSoundEntry() )
|
|
{
|
|
GetSoundBrowser()->JumpToItem( wave->GetOwnerSoundEntry() );
|
|
}
|
|
}
|
|
}
|
|
|
|
void CWorkspaceManager::OnCheckout()
|
|
{
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( !item )
|
|
return;
|
|
|
|
item->Checkout();
|
|
|
|
GetBrowser()->PopulateTree();
|
|
|
|
OnUpdateTitle();
|
|
}
|
|
|
|
void CWorkspaceManager::OnCheckin()
|
|
{
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( !item )
|
|
return;
|
|
|
|
item->Checkin();
|
|
|
|
GetBrowser()->PopulateTree();
|
|
|
|
OnUpdateTitle();
|
|
}
|
|
|
|
void CWorkspaceManager::OnMoveUp()
|
|
{
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( !item )
|
|
return;
|
|
|
|
ITreeItem *parent = item->GetParentItem();
|
|
if ( !parent )
|
|
return;
|
|
|
|
parent->MoveChildUp( item );
|
|
|
|
parent->SetDirty( true );
|
|
|
|
GetBrowser()->PopulateTree();
|
|
|
|
OnUpdateTitle();
|
|
|
|
GetBrowser()->JumpTo( item );
|
|
}
|
|
|
|
void CWorkspaceManager::OnMoveDown()
|
|
{
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( !item )
|
|
return;
|
|
|
|
ITreeItem *parent = item->GetParentItem();
|
|
if ( !parent )
|
|
return;
|
|
|
|
parent->MoveChildDown( item );
|
|
|
|
parent->SetDirty( true );
|
|
|
|
GetBrowser()->PopulateTree();
|
|
|
|
OnUpdateTitle();
|
|
|
|
GetBrowser()->JumpTo( item );
|
|
}
|
|
|
|
void CWorkspaceManager::SetWorkspaceDirty()
|
|
{
|
|
CWorkspace *ws = GetBrowser()->GetWorkspace();
|
|
if ( ws )
|
|
{
|
|
ws->SetDirty( true );
|
|
}
|
|
OnUpdateTitle();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CWorkspaceManager::OnSoundProperties()
|
|
{
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( !item )
|
|
return;
|
|
|
|
CSoundEntry *entry = item->GetSoundEntry();
|
|
if ( !entry )
|
|
return;
|
|
|
|
CSoundParams params;
|
|
memset( ¶ms, 0, sizeof( params ) );
|
|
|
|
Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Sound Properties" );
|
|
|
|
params.items.AddToTail( entry );
|
|
|
|
SoundProperties( ¶ms );
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CWorkspaceManager::OnWaveProperties()
|
|
{
|
|
ITreeItem *item = GetBrowser()->GetSelectedItem();
|
|
if ( !item )
|
|
return;
|
|
|
|
CWaveFile *wave = item->GetWaveFile();
|
|
if ( !wave )
|
|
return;
|
|
|
|
CWaveParams params;
|
|
memset( ¶ms, 0, sizeof( params ) );
|
|
|
|
Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Wave Properties" );
|
|
|
|
params.items.AddToTail( wave );
|
|
|
|
WaveProperties( ¶ms );
|
|
}
|