Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

964 lines
20 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "workspacebrowser.h"
  8. #include "workspace.h"
  9. #include "project.h"
  10. #include <windows.h>
  11. #include "resource.h"
  12. #include "project.h"
  13. #include "vcdfile.h"
  14. #include "soundentry.h"
  15. #include "scene.h"
  16. #include "workspacemanager.h"
  17. #include "soundbrowser.h"
  18. #include "SoundEmitterSystem/isoundemittersystembase.h"
  19. #include "iscenemanagersound.h"
  20. #include "snd_wave_source.h"
  21. #include "cmdlib.h"
  22. #include "tabwindow.h"
  23. #include "soundproperties.h"
  24. #include "soundproperties_multiple.h"
  25. #include "wavebrowser.h"
  26. #include "wavefile.h"
  27. #include "inputproperties.h"
  28. #include "drawhelper.h"
  29. #include "utlbuffer.h"
  30. #define ENTRY_ALLSOUNDS "AllSounds"
  31. #define ENTRY_ALL_INDEX 0
  32. #define ENTRY_SEARCHRESULTS "Search results"
  33. #define ENTRY_SEARCH_INDEX 1
  34. enum
  35. {
  36. // Controls
  37. IDC_SB_LISTVIEW = 101,
  38. IDC_SB_FILTERTAB,
  39. // Messages
  40. IDC_SB_PLAY = 1000,
  41. IDC_SB_SOUNDPROPERTIES,
  42. IDC_SB_SHOWINWAVEBROWSER,
  43. IDC_SB_ADDSOUND,
  44. IDC_SB_REMOVESOUND,
  45. IDC_SB_GETSENTENCE,
  46. };
  47. enum
  48. {
  49. COL_SOUND = 0,
  50. COL_COUNT,
  51. COL_WAV,
  52. COL_SENTENCE,
  53. COL_CHANNEL,
  54. COL_VOLUME,
  55. COL_SOUNDLEVEL,
  56. COL_PITCH,
  57. COL_SCRIPT,
  58. COL_CC,
  59. };
  60. class CSoundList : public mxListView
  61. {
  62. public:
  63. CSoundList( mxWindow *parent, int id = 0 )
  64. : mxListView( parent, 0, 0, 0, 0, id )
  65. {
  66. // SendMessage ( (HWND)getHandle(), WM_SETFONT, (WPARAM) (HFONT) GetStockObject (ANSI_FIXED_FONT), MAKELPARAM (TRUE, 0));
  67. //HWND wnd = (HWND)getHandle();
  68. //DWORD style = GetWindowLong( wnd, GWL_STYLE );
  69. //style |= LVS_SORTASCENDING;
  70. //SetWindowLong( wnd, GWL_STYLE, style );
  71. //SceneManager_AddWindowStyle( this, LVS_SORTASCENDING );
  72. // Add column headers
  73. insertTextColumn( COL_SOUND, 200, "Sound" );
  74. insertTextColumn( COL_COUNT, 20, "#" );
  75. insertTextColumn( COL_WAV, 220, "WAV Filename" );
  76. insertTextColumn( COL_SENTENCE, 300, "Sentence Text" );
  77. insertTextColumn( COL_CHANNEL, 100, "Channel" );
  78. insertTextColumn( COL_VOLUME, 100, "Volume" );
  79. insertTextColumn( COL_SOUNDLEVEL, 120, "Soundlevel" );
  80. insertTextColumn( COL_PITCH, 100, "Pitch" );
  81. insertTextColumn( COL_SCRIPT, 150, "Script File" );
  82. insertTextColumn( COL_CC, 300, "CC Text" );
  83. }
  84. };
  85. class CSoundFilterTab : public CTabWindow
  86. {
  87. public:
  88. typedef CTabWindow BaseClass;
  89. CSoundFilterTab( mxWindow *parent, int x, int y, int w, int h, int id = 0, int style = 0 ) :
  90. CTabWindow( parent, x, y, w, h, id, style )
  91. {
  92. SetInverted( true );
  93. SetRowHeight( 20 );
  94. }
  95. virtual void ShowRightClickMenu( int mx, int my )
  96. {
  97. // Nothing
  98. }
  99. void Init( CUtlSymbolTable& table, CUtlVector< CUtlSymbol >& scripts )
  100. {
  101. add( ENTRY_ALLSOUNDS );
  102. add( ENTRY_SEARCHRESULTS );
  103. int c = scripts.Count();
  104. for ( int i = 0; i < c; i++ )
  105. {
  106. CUtlSymbol& sym = scripts[ i ];
  107. add( table.String( sym ) );
  108. }
  109. select( 0 );
  110. }
  111. void UpdatePrefixes()
  112. {
  113. int c = getItemCount();
  114. // Skip All and search results
  115. for ( int i = 2; i < c; i++ )
  116. {
  117. setPrefix( i, "" );
  118. char const *script = getLabel( i );
  119. if ( !script )
  120. continue;
  121. int scriptindex = g_pSoundEmitterSystem->FindSoundScript( va( "scripts/%s.txt", script ) );
  122. if ( scriptindex < 0 )
  123. continue;
  124. if ( g_pSoundEmitterSystem->IsSoundScriptDirty( scriptindex ) )
  125. {
  126. setPrefix( i, "* " );
  127. }
  128. }
  129. RecomputeLayout( w2() );
  130. redraw();
  131. }
  132. };
  133. class COptionsWindow : public mxWindow
  134. {
  135. typedef mxWindow BaseClass;
  136. public:
  137. enum
  138. {
  139. IDC_VOICE_ONLY = 1000,
  140. IDC_PLAY_SOUND,
  141. IDC_STOP_SOUNDS,
  142. IDC_SEARCH,
  143. };
  144. COptionsWindow( CSoundBrowser *browser ) : BaseClass( browser, 0, 0, 0, 0 ), m_pBrowser( browser )
  145. {
  146. SceneManager_AddWindowStyle( this, WS_CLIPSIBLINGS | WS_CLIPCHILDREN );
  147. m_szSearchString[0]=0;
  148. m_pChanVoiceOnly = new mxCheckBox( this, 0, 0, 0, 0, "CHAN_VOICE only", IDC_VOICE_ONLY );
  149. m_pChanVoiceOnly->setChecked( true );
  150. m_pPlay = new mxButton( this, 0, 0, 0, 0, "Play", IDC_PLAY_SOUND );
  151. m_pStopSounds = new mxButton( this, 0, 0, 0, 0, "Stop Sounds", IDC_STOP_SOUNDS );
  152. m_pSearch = new mxButton( this, 0, 0, 0, 0, "Search...", IDC_SEARCH );
  153. m_pSearchString = new mxLabel( this, 0, 0, 0, 0, "" );
  154. }
  155. bool PaintBackground( void )
  156. {
  157. redraw();
  158. return false;
  159. }
  160. virtual void redraw()
  161. {
  162. CDrawHelper drawHelper( this, GetSysColor( COLOR_BTNFACE ) );
  163. }
  164. virtual int handleEvent( mxEvent *event )
  165. {
  166. int iret = 0;
  167. switch ( event->event )
  168. {
  169. default:
  170. break;
  171. case mxEvent::Size:
  172. {
  173. iret = 1;
  174. int split = 120;
  175. int x = 1;
  176. m_pPlay->setBounds( x, 1, split, h2() - 2 );
  177. x += split + 10;
  178. m_pStopSounds->setBounds( x, 1, split, h2()-2 );
  179. x += split + 10;
  180. m_pChanVoiceOnly->setBounds( x, 1, split, h2() - 2 );
  181. x += split + 10;
  182. m_pSearch->setBounds( x, 1, split, h2() - 2 );
  183. x += split + 10;
  184. m_pSearchString->setBounds( x, 2, split * 2, h2() - 4 );
  185. x += split * 2 + 10;
  186. }
  187. break;
  188. case mxEvent::Action:
  189. {
  190. switch ( event->action )
  191. {
  192. case IDC_STOP_SOUNDS:
  193. {
  194. iret = 1;
  195. sound->StopAll();
  196. }
  197. break;
  198. case IDC_PLAY_SOUND:
  199. {
  200. iret = 1;
  201. m_pBrowser->OnPlay();
  202. }
  203. break;
  204. case IDC_VOICE_ONLY:
  205. {
  206. iret = 1;
  207. m_pBrowser->RepopulateTree();
  208. };
  209. break;
  210. case IDC_SEARCH:
  211. {
  212. iret = 1;
  213. OnSearch();
  214. };
  215. break;
  216. default:
  217. break;
  218. }
  219. }
  220. break;
  221. }
  222. return iret;
  223. }
  224. bool IsChanVoiceOnly() const
  225. {
  226. return m_pChanVoiceOnly->isChecked();
  227. }
  228. char const *GetSearchString()
  229. {
  230. return m_szSearchString;
  231. }
  232. void OnSearch()
  233. {
  234. CInputParams params;
  235. memset( &params, 0, sizeof( params ) );
  236. Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Search" );
  237. Q_strcpy( params.m_szPrompt, "Find:" );
  238. Q_strcpy( params.m_szInputText, m_szSearchString );
  239. if ( !InputProperties( &params ) )
  240. return;
  241. Q_strcpy( m_szSearchString, params.m_szInputText );
  242. m_pSearchString->setLabel( va( "Search: '%s'", GetSearchString() ) );
  243. m_pBrowser->OnSearch();
  244. }
  245. private:
  246. mxCheckBox *m_pChanVoiceOnly;
  247. mxButton *m_pStopSounds;
  248. mxButton *m_pPlay;
  249. mxButton *m_pSearch;
  250. mxLabel *m_pSearchString;
  251. CSoundBrowser *m_pBrowser;
  252. char m_szSearchString[ 256 ];
  253. };
  254. //-----------------------------------------------------------------------------
  255. // Purpose:
  256. // Input : *parent -
  257. //-----------------------------------------------------------------------------
  258. CSoundBrowser::CSoundBrowser( mxWindow *parent, CWorkspaceManager *manager, int id ) :
  259. BaseClass( parent, 0, 0, 0, 0, "Sound Browser", id )
  260. {
  261. m_pManager = manager;
  262. SceneManager_MakeToolWindow( this, false );
  263. m_pListView = new CSoundList( this, IDC_SB_LISTVIEW );
  264. m_pFilter = new CSoundFilterTab( this, 0, 0, 0, 0, IDC_SB_FILTERTAB );
  265. m_pOptions = new COptionsWindow( this );
  266. HIMAGELIST list = GetWorkspaceManager()->CreateImageList();
  267. // Associate the image list with the tree-view control.
  268. m_pListView->setImageList( (void *)list );
  269. LoadAllSounds();
  270. m_pFilter->select( 0 );
  271. RepopulateTree();
  272. }
  273. //-----------------------------------------------------------------------------
  274. // Purpose:
  275. //-----------------------------------------------------------------------------
  276. void CSoundBrowser::OnDelete()
  277. {
  278. RemoveAllSounds();
  279. }
  280. //-----------------------------------------------------------------------------
  281. // Purpose:
  282. // Input : *event -
  283. // Output : int
  284. //-----------------------------------------------------------------------------
  285. int CSoundBrowser::handleEvent( mxEvent *event )
  286. {
  287. int iret = 0;
  288. switch ( event->event )
  289. {
  290. default:
  291. break;
  292. case mxEvent::Action:
  293. {
  294. iret = 1;
  295. switch ( event->action )
  296. {
  297. default:
  298. {
  299. iret = 0;
  300. }
  301. break;
  302. case IDC_SB_FILTERTAB:
  303. {
  304. RepopulateTree();
  305. }
  306. break;
  307. case IDC_SB_LISTVIEW:
  308. {
  309. bool rightmouse = ( event->flags == mxEvent::RightClicked ) ? true : false;
  310. bool doubleclicked = ( event->flags == mxEvent::DoubleClicked ) ? true : false;
  311. if ( rightmouse )
  312. {
  313. ShowContextMenu();
  314. }
  315. else if ( doubleclicked )
  316. {
  317. if ( m_pListView->getNumSelected() == 1 )
  318. {
  319. int index = m_pListView->getNextSelectedItem( -1 );
  320. if ( index >= 0 )
  321. {
  322. CSoundEntry *se = (CSoundEntry *)m_pListView->getUserData( index, 0 );
  323. if ( se )
  324. {
  325. se->Play();
  326. CWaveBrowser *wb = GetWorkspaceManager()->GetWaveBrowser();
  327. if ( wb && se->GetWaveCount() > 0 )
  328. {
  329. CWaveFile *firstwave = se->GetWave( 0 );
  330. Assert( firstwave );
  331. if ( firstwave )
  332. {
  333. wb->JumpToItem( firstwave );
  334. }
  335. }
  336. }
  337. }
  338. }
  339. }
  340. }
  341. break;
  342. case IDC_SB_PLAY:
  343. {
  344. OnPlay();
  345. }
  346. break;
  347. case IDC_SB_GETSENTENCE:
  348. {
  349. OnGetSentence();
  350. }
  351. break;
  352. case IDC_SB_SOUNDPROPERTIES:
  353. {
  354. OnSoundProperties();
  355. }
  356. break;
  357. case IDC_SB_SHOWINWAVEBROWSER:
  358. {
  359. OnShowInWaveBrowser();
  360. }
  361. break;
  362. case IDC_SB_ADDSOUND:
  363. {
  364. OnAddSound();
  365. }
  366. break;
  367. case IDC_SB_REMOVESOUND:
  368. {
  369. OnRemoveSound();
  370. }
  371. break;
  372. }
  373. }
  374. break;
  375. case mxEvent::Size:
  376. {
  377. int optionsh = 20;
  378. int filterh = m_pFilter->GetBestHeight( w2() );
  379. m_pOptions->setBounds( 0, 0, w2(), optionsh );
  380. m_pListView->setBounds( 0, optionsh, w2(), h2() - filterh - optionsh );
  381. m_pFilter->setBounds( 0, h2() - filterh, w2(), filterh );
  382. GetWorkspaceManager()->SetWorkspaceDirty();
  383. iret = 1;
  384. }
  385. break;
  386. case mxEvent::Close:
  387. {
  388. iret = 1;
  389. }
  390. break;
  391. }
  392. return iret;
  393. }
  394. static bool NameLessFunc( CSoundEntry *const& name1, CSoundEntry *const& name2 )
  395. {
  396. if ( Q_stricmp( name1->GetName(), name2->GetName() ) < 0 )
  397. return true;
  398. return false;
  399. }
  400. void CSoundBrowser::LoadAllSounds()
  401. {
  402. RemoveAllSounds();
  403. // int c = g_pSoundEmitterSystem->GetSoundCount();
  404. int added = 0;
  405. int i;
  406. for ( i = g_pSoundEmitterSystem->First(); i != g_pSoundEmitterSystem->InvalidIndex(); i = g_pSoundEmitterSystem->Next( i ) )
  407. {
  408. char const *name = g_pSoundEmitterSystem->GetSoundName( i );
  409. CSoundEntry *se = new CSoundEntry( NULL, name );
  410. m_AllSounds.AddToTail( se );
  411. char filebase [ 512 ];
  412. Q_FileBase( g_pSoundEmitterSystem->GetSourceFileForSound( i ), filebase, sizeof( filebase ) );
  413. // Add script file symbol
  414. CUtlSymbol script_sym = m_ScriptTable.AddString( filebase );
  415. if ( m_Scripts.Find( script_sym ) == m_Scripts.InvalidIndex() )
  416. {
  417. m_Scripts.AddToTail( script_sym );
  418. }
  419. ++added;
  420. if ( !( added % 500 ) )
  421. {
  422. // Con_Printf( "CSoundBrowser: loaded %i sounds\n", added );
  423. }
  424. }
  425. m_pFilter->Init( m_ScriptTable, m_Scripts );
  426. }
  427. void CSoundBrowser::RemoveAllSounds()
  428. {
  429. int c = m_AllSounds.Count();
  430. for ( int i = 0; i < c; i++ )
  431. {
  432. CSoundEntry *se = m_AllSounds[ i ];
  433. delete se;
  434. }
  435. m_AllSounds.RemoveAll();
  436. m_Scripts.RemoveAll();
  437. m_CurrentSelection.RemoveAll();
  438. }
  439. //-----------------------------------------------------------------------------
  440. // Purpose:
  441. //-----------------------------------------------------------------------------
  442. void CSoundBrowser::PopulateTree( bool voiceonly, char const *scriptonly )
  443. {
  444. int i;
  445. CUtlRBTree< CSoundEntry *, int > m_Sorted( 0, 0, NameLessFunc );
  446. bool textsearch = false;
  447. char const *texttofind = NULL;
  448. if ( scriptonly )
  449. {
  450. if ( !Q_stricmp( scriptonly, ENTRY_ALLSOUNDS ) )
  451. {
  452. scriptonly = NULL;
  453. }
  454. else if ( !Q_stricmp( scriptonly, ENTRY_SEARCHRESULTS ) )
  455. {
  456. scriptonly = NULL;
  457. textsearch = true;
  458. texttofind = GetSearchString();
  459. }
  460. }
  461. int c = m_AllSounds.Count();
  462. for ( i = 0; i < c; i++ )
  463. {
  464. CSoundEntry *se = m_AllSounds[ i ];
  465. char const *name = se->GetName();
  466. CSoundParametersInternal *params = se->GetSoundParameters();
  467. if ( !params )
  468. continue;
  469. if ( voiceonly && params->GetChannel() != CHAN_VOICE )
  470. continue;
  471. if ( scriptonly )
  472. {
  473. if ( Q_stricmp( scriptonly, se->GetScriptFile() ) )
  474. continue;
  475. }
  476. if ( textsearch && texttofind )
  477. {
  478. bool keep = false;
  479. if ( Q_stristr( name, texttofind ) )
  480. {
  481. keep = true;
  482. }
  483. else
  484. {
  485. int waveCount = se->GetWaveCount();
  486. for ( int wave = 0; wave < waveCount; wave++ )
  487. {
  488. CWaveFile *w = se->GetWave( wave );
  489. if ( !w )
  490. continue;
  491. char const *wavename = w->GetFileName();
  492. if ( !wavename )
  493. {
  494. Assert( 0 );
  495. continue;
  496. }
  497. if ( !Q_stristr( wavename, texttofind ) )
  498. {
  499. continue;
  500. }
  501. keep = true;
  502. break;
  503. }
  504. }
  505. if ( !keep )
  506. {
  507. continue;
  508. }
  509. }
  510. m_Sorted.Insert( se );
  511. }
  512. // Repopulate tree
  513. m_pListView->removeAll();
  514. int loadcount = 0;
  515. m_pListView->setDrawingEnabled( false );
  516. for ( i = m_Sorted.FirstInorder(); i != m_Sorted.InvalidIndex(); i = m_Sorted.NextInorder( i ) )
  517. {
  518. CSoundEntry *se = m_Sorted[ i ];
  519. char const *name = se->GetName();
  520. CSoundParametersInternal *params = se->GetSoundParameters();
  521. if ( !params )
  522. continue;
  523. int slot = m_pListView->add( name );
  524. m_pListView->setUserData( slot, COL_SOUND, (void *)se );
  525. m_pListView->setImage( slot, COL_SOUND, se->GetIconIndex() );
  526. int waveCount = params->NumSoundNames();
  527. if ( waveCount >= 1 )
  528. {
  529. m_pListView->setLabel( slot, COL_COUNT, waveCount > 1 ? va( "%i", waveCount ) : "" );
  530. m_pListView->setLabel( slot, COL_WAV, g_pSoundEmitterSystem->GetWaveName( params->GetSoundNames()[ 0 ].symbol ) );
  531. }
  532. m_pListView->setLabel( slot, COL_SENTENCE, se->GetSentenceText( 0 ) );
  533. m_pListView->setLabel( slot, COL_CHANNEL, params->ChannelToString() );
  534. m_pListView->setLabel( slot, COL_VOLUME, params->VolumeToString() );
  535. m_pListView->setLabel( slot, COL_SOUNDLEVEL, params->SoundLevelToString() );
  536. m_pListView->setLabel( slot, COL_PITCH, params->PitchToString() );
  537. wchar_t buf[ 1024 ];
  538. se->GetCCText( buf, 1024 );
  539. m_pListView->setLabel( slot, COL_CC, buf );
  540. char filebase [ 512 ];
  541. int soundIndex = g_pSoundEmitterSystem->GetSoundIndex( name );
  542. Q_FileBase( g_pSoundEmitterSystem->GetSourceFileForSound( soundIndex ), filebase, sizeof( filebase ) );
  543. m_pListView->setLabel( slot, COL_SCRIPT, filebase );
  544. ++loadcount;
  545. }
  546. m_pListView->setDrawingEnabled( true );
  547. // Con_Printf( "CSoundBrowser: selected %i sounds\n", loadcount );
  548. }
  549. CWorkspaceManager *CSoundBrowser::GetManager()
  550. {
  551. return m_pManager;
  552. }
  553. void CSoundBrowser::RepopulateTree()
  554. {
  555. bool voiceonly = m_pOptions->IsChanVoiceOnly();
  556. int slot = m_pFilter->getSelectedIndex();
  557. if ( 0 >= slot )
  558. {
  559. PopulateTree( voiceonly, NULL );
  560. }
  561. else
  562. {
  563. PopulateTree( voiceonly, m_pFilter->getLabel( slot ) );
  564. }
  565. m_pFilter->UpdatePrefixes();
  566. }
  567. void CSoundBrowser::BuildSelectionList( CUtlVector< CSoundEntry * >& selected )
  568. {
  569. selected.RemoveAll();
  570. int idx = -1;
  571. do
  572. {
  573. idx = m_pListView->getNextSelectedItem( idx );
  574. if ( idx != -1 )
  575. {
  576. CSoundEntry *se = (CSoundEntry *)m_pListView->getUserData( idx, 0 );
  577. if ( se )
  578. {
  579. selected.AddToTail( se );
  580. }
  581. }
  582. } while ( idx != -1 );
  583. }
  584. void CSoundBrowser::ShowContextMenu( void )
  585. {
  586. BuildSelectionList( m_CurrentSelection );
  587. if ( m_CurrentSelection.Count() <= 0 )
  588. return;
  589. POINT pt;
  590. GetCursorPos( &pt );
  591. ScreenToClient( (HWND)getHandle(), &pt );
  592. // New scene, edit comments
  593. mxPopupMenu *pop = new mxPopupMenu();
  594. if ( m_CurrentSelection.Count() == 1 )
  595. {
  596. pop->add ("&Play", IDC_SB_PLAY );
  597. pop->addSeparator();
  598. }
  599. pop->add( "Refresh sentence data", IDC_SB_GETSENTENCE );
  600. pop->add( "Add sound entry...", IDC_SB_ADDSOUND );
  601. if ( m_CurrentSelection.Count() >= 1 )
  602. {
  603. pop->add( "Remove sound(s)", IDC_SB_REMOVESOUND );
  604. }
  605. pop->addSeparator();
  606. pop->add( "Show in Wave Browser", IDC_SB_SHOWINWAVEBROWSER );
  607. pop->add( "&Properties...", IDC_SB_SOUNDPROPERTIES );
  608. pop->popup( this, pt.x, pt.y );
  609. }
  610. void CSoundBrowser::OnPlay()
  611. {
  612. BuildSelectionList( m_CurrentSelection );
  613. if ( m_CurrentSelection.Count() == 1 )
  614. {
  615. CSoundEntry *se = m_CurrentSelection[ 0 ];
  616. if ( se )
  617. {
  618. se->Play();
  619. }
  620. }
  621. }
  622. void CSoundBrowser::JumpToItem( CSoundEntry *se )
  623. {
  624. char const *script = se->GetScriptFile();
  625. bool voiceonly = m_pOptions->IsChanVoiceOnly();
  626. if ( !script || !script[ 0 ] )
  627. {
  628. PopulateTree( voiceonly, NULL );
  629. }
  630. else
  631. {
  632. PopulateTree( voiceonly, script );
  633. }
  634. int idx = 0;
  635. int c = m_pListView->getItemCount();
  636. for ( ; idx < c; idx++ )
  637. {
  638. CSoundEntry *item = (CSoundEntry *)m_pListView->getUserData( idx, 0 );
  639. if ( !Q_stricmp( item->GetName(), se->GetName() ) )
  640. {
  641. break;
  642. }
  643. }
  644. if ( idx < c )
  645. {
  646. m_pListView->scrollToItem( idx );
  647. }
  648. }
  649. void CSoundBrowser::OnSoundProperties()
  650. {
  651. BuildSelectionList( m_CurrentSelection );
  652. if ( m_CurrentSelection.Count() < 1 )
  653. {
  654. Con_Printf( "No selection\n" );
  655. return;
  656. }
  657. CSoundParams params;
  658. memset( &params, 0, sizeof( params ) );
  659. Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Sound Properties" );
  660. int c = m_CurrentSelection.Count();
  661. for ( int i = 0 ; i < c; i++ )
  662. {
  663. CSoundEntry *entry = m_CurrentSelection[ i ];
  664. if ( !entry )
  665. continue;
  666. params.items.AddToTail( entry );
  667. }
  668. if ( params.items.Count() > 1 )
  669. {
  670. SoundProperties_Multiple( &params );
  671. }
  672. else
  673. {
  674. SoundProperties( &params );
  675. }
  676. }
  677. void CSoundBrowser::OnShowInWaveBrowser()
  678. {
  679. if ( m_pListView->getNumSelected() == 1 )
  680. {
  681. int index = m_pListView->getNextSelectedItem( -1 );
  682. if ( index >= 0 )
  683. {
  684. CSoundEntry *se = (CSoundEntry *)m_pListView->getUserData( index, 0 );
  685. if ( se )
  686. {
  687. CWaveBrowser *wb = GetWorkspaceManager()->GetWaveBrowser();
  688. if ( wb && se->GetWaveCount() > 0 )
  689. {
  690. CWaveFile *firstwave = se->GetWave( 0 );
  691. Assert( firstwave );
  692. if ( firstwave )
  693. {
  694. wb->JumpToItem( firstwave );
  695. }
  696. }
  697. }
  698. }
  699. }
  700. }
  701. void CSoundBrowser::OnSearch()
  702. {
  703. m_pFilter->select( ENTRY_SEARCH_INDEX );
  704. RepopulateTree();
  705. }
  706. char const *CSoundBrowser::GetSearchString()
  707. {
  708. return m_pOptions->GetSearchString();
  709. }
  710. void CSoundBrowser::OnAddSound()
  711. {
  712. CSoundParams params;
  713. memset( &params, 0, sizeof( params ) );
  714. params.addsound = true;
  715. Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "New Sound" );
  716. if ( !SoundProperties( &params ) )
  717. return;
  718. if ( params.items.Count() == 1 )
  719. {
  720. CSoundEntry *newItem = params.items[ 0 ];
  721. m_AllSounds.AddToTail( newItem );
  722. int slot = g_pSoundEmitterSystem->GetSoundIndex( newItem->GetName() );
  723. if ( g_pSoundEmitterSystem->IsValidIndex( slot ) )
  724. {
  725. CSoundParametersInternal *p = g_pSoundEmitterSystem->InternalGetParametersForSound( slot );
  726. if ( p )
  727. {
  728. CWaveBrowser *wb = GetWorkspaceManager()->GetWaveBrowser();
  729. Assert( wb );
  730. int waveCount = p->NumSoundNames();
  731. for ( int wave = 0; wave < waveCount; wave++ )
  732. {
  733. char const *wavname = g_pSoundEmitterSystem->GetWaveName( p->GetSoundNames()[ wave ].symbol );
  734. if ( wavname )
  735. {
  736. CWaveFile *wavefile = wb->FindEntry( wavname, true );
  737. if ( wavefile )
  738. {
  739. newItem->AddWave( wavefile );
  740. }
  741. }
  742. }
  743. }
  744. }
  745. }
  746. // Repopulate things
  747. GetWorkspaceManager()->RefreshBrowsers();
  748. }
  749. void CSoundBrowser::OnRemoveSound()
  750. {
  751. BuildSelectionList( m_CurrentSelection );
  752. if ( m_CurrentSelection.Count() < 1 )
  753. {
  754. Con_Printf( "No selection\n" );
  755. return;
  756. }
  757. int c = m_CurrentSelection.Count();
  758. for ( int i = c - 1; i >= 0 ; i-- )
  759. {
  760. CSoundEntry *se = m_CurrentSelection[ i ];
  761. Assert( se );
  762. // FIXME: See if still referenced by a vcd?
  763. g_pSoundEmitterSystem->RemoveSound( se->GetName() );
  764. m_AllSounds.FindAndRemove( se );
  765. delete se;
  766. }
  767. // Repopulate things
  768. GetWorkspaceManager()->RefreshBrowsers();
  769. }
  770. void CSoundBrowser::OnGetSentence()
  771. {
  772. BuildSelectionList( m_CurrentSelection );
  773. if ( m_CurrentSelection.Count() < 1 )
  774. {
  775. Con_Printf( "No selection\n" );
  776. return;
  777. }
  778. int c = m_CurrentSelection.Count();
  779. for ( int i = c - 1; i >= 0 ; i-- )
  780. {
  781. CSoundEntry *se = m_CurrentSelection[ i ];
  782. Assert( se );
  783. int c = se->GetWaveCount();
  784. for ( int i = 0; i < c; ++i )
  785. {
  786. CWaveFile *wav = se->GetWave( i );
  787. if ( !wav->HasLoadedSentenceInfo() )
  788. {
  789. wav->EnsureSentence();
  790. }
  791. }
  792. }
  793. // Repopulate things
  794. GetWorkspaceManager()->RefreshBrowsers();
  795. }