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.

1206 lines
30 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include <stdio.h>
  9. #include <mxtk/mxPopupMenu.h>
  10. #include "hlfaceposer.h"
  11. #include "choreochannelwidget.h"
  12. #include "choreoeventwidget.h"
  13. #include "choreoactorwidget.h"
  14. #include "choreochannel.h"
  15. #include "choreowidgetdrawhelper.h"
  16. #include "choreoview.h"
  17. #include "choreoevent.h"
  18. #include "choreoviewcolors.h"
  19. #include "utlrbtree.h"
  20. #include "utllinkedlist.h"
  21. #include "iclosecaptionmanager.h"
  22. #include "PhonemeEditor.h"
  23. #include "SoundEmitterSystem/isoundemittersystembase.h"
  24. #include "filesystem.h"
  25. #define AUDIO_HEIGHT 18
  26. #define STREAM_FONT "Tahoma"
  27. //-----------------------------------------------------------------------------
  28. // Purpose:
  29. // Input : *parent -
  30. //-----------------------------------------------------------------------------
  31. CChoreoChannelWidget::CChoreoChannelWidget( CChoreoActorWidget *parent )
  32. : CChoreoWidget( parent )
  33. {
  34. m_pChannel = NULL;
  35. m_pParent = parent;
  36. m_bHasAudio = false;
  37. m_nBaseHeight = 0;
  38. m_nSelectorEventIndex = -1;
  39. }
  40. //-----------------------------------------------------------------------------
  41. // Purpose:
  42. //-----------------------------------------------------------------------------
  43. CChoreoChannelWidget::~CChoreoChannelWidget( void )
  44. {
  45. for ( int i = 0 ; i < m_Events.Size(); i++ )
  46. {
  47. CChoreoEventWidget *e = m_Events[ i ];
  48. delete e;
  49. }
  50. m_Events.RemoveAll();
  51. }
  52. //-----------------------------------------------------------------------------
  53. // Purpose: Create child windows
  54. //-----------------------------------------------------------------------------
  55. void CChoreoChannelWidget::Create( void )
  56. {
  57. Assert( m_pChannel );
  58. // Create objects for children
  59. for ( int i = 0; i < m_pChannel->GetNumEvents(); i++ )
  60. {
  61. CChoreoEvent *e = m_pChannel->GetEvent( i );
  62. Assert( e );
  63. if ( !e )
  64. {
  65. continue;
  66. }
  67. CChoreoEventWidget *eventWidget = new CChoreoEventWidget( this );
  68. eventWidget->SetEvent( e );
  69. eventWidget->Create();
  70. AddEvent( eventWidget );
  71. }
  72. }
  73. //-----------------------------------------------------------------------------
  74. // Purpose:
  75. // Input : mx -
  76. // Output : float
  77. //-----------------------------------------------------------------------------
  78. float CChoreoChannelWidget::GetTimeForMousePosition( int mx )
  79. {
  80. int dx = mx - m_pView->GetLabelWidth();
  81. float windowfrac = ( float ) dx / ( float ) ( w() - m_pView->GetLabelWidth() );
  82. float time = m_pView->GetStartTime() + windowfrac * ( m_pView->GetEndTime() - m_pView->GetStartTime() );
  83. return time;
  84. }
  85. static bool EventStartTimeLessFunc( CChoreoEventWidget * const &p1, CChoreoEventWidget * const &p2 )
  86. {
  87. CChoreoEventWidget *w1;
  88. CChoreoEventWidget *w2;
  89. w1 = const_cast< CChoreoEventWidget * >( p1 );
  90. w2 = const_cast< CChoreoEventWidget * >( p2 );
  91. CChoreoEvent *e1;
  92. CChoreoEvent *e2;
  93. e1 = w1->GetEvent();
  94. e2 = w2->GetEvent();
  95. return e1->GetStartTime() < e2->GetStartTime();
  96. }
  97. void CChoreoChannelWidget::LayoutEventInRow( CChoreoEventWidget *event, int row, RECT& rc )
  98. {
  99. int itemHeight = BaseClass::GetItemHeight();
  100. RECT rcEvent;
  101. rcEvent.left = m_pView->GetPixelForTimeValue( event->GetEvent()->GetStartTime() );
  102. if ( event->GetEvent()->HasEndTime() )
  103. {
  104. rcEvent.right = m_pView->GetPixelForTimeValue( event->GetEvent()->GetEndTime() );
  105. }
  106. else
  107. {
  108. rcEvent.right = rcEvent.left + 8;
  109. }
  110. rcEvent.top = rc.top + ( row ) * itemHeight + 2;
  111. rcEvent.bottom = rc.top + ( row + 1 ) * itemHeight - 2;
  112. event->Layout( rcEvent );
  113. }
  114. static bool EventCollidesWithRows( CUtlLinkedList< CChoreoEventWidget *, int >& list, CChoreoEventWidget *event )
  115. {
  116. float st = event->GetEvent()->GetStartTime();
  117. float ed = event->GetEvent()->HasEndTime() ? event->GetEvent()->GetEndTime() : event->GetEvent()->GetStartTime();
  118. for ( int i = list.Head(); i != list.InvalidIndex(); i = list.Next( i ) )
  119. {
  120. CChoreoEvent *test = list[ i ]->GetEvent();
  121. float teststart = test->GetStartTime();
  122. float testend = test->HasEndTime() ? test->GetEndTime() : test->GetStartTime();
  123. // See if spans overlap
  124. if ( teststart >= ed )
  125. continue;
  126. if ( testend <= st )
  127. continue;
  128. return true;
  129. }
  130. return false;
  131. }
  132. int CChoreoChannelWidget::GetVerticalStackingCount( bool layout, RECT *rc )
  133. {
  134. CUtlRBTree< CChoreoEventWidget * > sorted( 0, 0, EventStartTimeLessFunc );
  135. CUtlVector< CUtlLinkedList< CChoreoEventWidget *, int > > rows;
  136. int i;
  137. // Sort items
  138. int c = m_Events.Size();
  139. for ( i = 0; i < c; i++ )
  140. {
  141. sorted.Insert( m_Events[ i ] );
  142. }
  143. for ( i = sorted.FirstInorder(); i != sorted.InvalidIndex(); i = sorted.NextInorder( i ) )
  144. {
  145. CChoreoEventWidget *event = sorted[ i ];
  146. Assert( event );
  147. if ( !rows.Count() )
  148. {
  149. rows.AddToTail();
  150. CUtlLinkedList< CChoreoEventWidget *, int >& list = rows[ 0 ];
  151. list.AddToHead( event );
  152. if ( layout )
  153. {
  154. LayoutEventInRow( event, 0, *rc );
  155. }
  156. continue;
  157. }
  158. // Does it come totally after what's in rows[0]?
  159. int rowCount = rows.Count();
  160. bool addrow = true;
  161. for ( int j = 0; j < rowCount; j++ )
  162. {
  163. CUtlLinkedList< CChoreoEventWidget *, int >& list = rows[ j ];
  164. if ( !EventCollidesWithRows( list, event ) )
  165. {
  166. // Update row event list
  167. list.AddToHead( event );
  168. addrow = false;
  169. if ( layout )
  170. {
  171. LayoutEventInRow( event, j, *rc );
  172. }
  173. break;
  174. }
  175. }
  176. if ( addrow )
  177. {
  178. // Add a new row
  179. int idx = rows.AddToTail();
  180. CUtlLinkedList< CChoreoEventWidget *, int >& list = rows[ idx ];
  181. list.AddToHead( event );
  182. if ( layout )
  183. {
  184. LayoutEventInRow( event, rows.Count() - 1, *rc );
  185. }
  186. }
  187. }
  188. return max( 1, rows.Count() );
  189. }
  190. int CChoreoChannelWidget::GetItemHeight( void )
  191. {
  192. int itemHeight = BaseClass::GetItemHeight();
  193. int stackCount = GetVerticalStackingCount( false, NULL );
  194. CheckHasAudio();
  195. int h = stackCount * itemHeight;
  196. // Remember the base height
  197. m_nBaseHeight = h;
  198. if ( m_bHasAudio && m_pView->GetShowCloseCaptionData() )
  199. {
  200. h += 2 * AUDIO_HEIGHT;
  201. }
  202. return h;
  203. }
  204. bool CChoreoChannelWidget::CheckHasAudio()
  205. {
  206. m_bHasAudio = false;
  207. // Create objects for children
  208. for ( int i = 0; i < m_Events.Size(); i++ )
  209. {
  210. CChoreoEventWidget *event = m_Events[ i ];
  211. if ( event->GetEvent()->GetType() == CChoreoEvent::SPEAK )
  212. {
  213. m_bHasAudio = true;
  214. break;
  215. }
  216. }
  217. return m_bHasAudio;
  218. }
  219. //-----------------------------------------------------------------------------
  220. // Purpose:
  221. // Input : rc -
  222. //-----------------------------------------------------------------------------
  223. void CChoreoChannelWidget::Layout( RECT& rc )
  224. {
  225. setBounds( rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top );
  226. GetVerticalStackingCount( true, &rc );
  227. CheckHasAudio();
  228. /*
  229. // Create objects for children
  230. for ( int i = 0; i < m_Events.Size(); i++ )
  231. {
  232. CChoreoEventWidget *event = m_Events[ i ];
  233. Assert( event );
  234. if ( !event )
  235. {
  236. continue;
  237. }
  238. RECT rcEvent;
  239. rcEvent.left = m_pView->GetPixelForTimeValue( event->GetEvent()->GetStartTime() );
  240. if ( event->GetEvent()->HasEndTime() )
  241. {
  242. rcEvent.right = m_pView->GetPixelForTimeValue( event->GetEvent()->GetEndTime() );
  243. }
  244. else
  245. {
  246. rcEvent.right = rcEvent.left + 8;
  247. }
  248. rcEvent.top = rc.top + 2;
  249. rcEvent.bottom = rc.bottom - 2;
  250. event->Layout( rcEvent );
  251. }
  252. */
  253. }
  254. //-----------------------------------------------------------------------------
  255. // Purpose:
  256. //-----------------------------------------------------------------------------
  257. void CChoreoChannelWidget::redraw( CChoreoWidgetDrawHelper& drawHelper )
  258. {
  259. if ( !getVisible() )
  260. return;
  261. CChoreoChannel *channel = GetChannel();
  262. if ( !channel )
  263. return;
  264. RECT rcText;
  265. rcText = getBounds();
  266. rcText.right = m_pView->GetLabelWidth();
  267. if ( !channel->GetActive() )
  268. {
  269. RECT rcBg = rcText;
  270. InflateRect( &rcBg, -5, -5 );
  271. drawHelper.DrawFilledRect( RGB( 210, 210, 210 ), rcBg );
  272. }
  273. RECT rcName = rcText;
  274. rcName.left += 20;
  275. char n[ 512 ];
  276. V_strcpy_safe( n, channel->GetName() );
  277. drawHelper.DrawColoredText( "Arial",
  278. m_pView->GetFontSize() + 2,
  279. FW_HEAVY,
  280. channel->GetActive() ? COLOR_CHOREO_CHANNELNAME : COLOR_CHOREO_ACTORNAME_INACTIVE,
  281. rcName, n );
  282. if ( !channel->GetActive() )
  283. {
  284. strcpy( n, "(inactive)" );
  285. RECT rcInactive = rcName;
  286. int len = drawHelper.CalcTextWidth( "Arial", m_pView->GetFontSize(), 500, n );
  287. rcInactive.left = rcInactive.right - len;
  288. //rcInactive.top += 3;
  289. //rcInactive.bottom = rcInactive.top + m_pView->GetFontSize() - 2;
  290. drawHelper.DrawColoredText( "Arial", m_pView->GetFontSize() - 2, 500,
  291. COLOR_CHOREO_ACTORNAME_INACTIVE, rcInactive, n );
  292. }
  293. rcName.left -= 20;
  294. RECT rcEventArea = getBounds();
  295. rcEventArea.left = m_pView->GetLabelWidth() + 1;
  296. rcEventArea.top -= 20;
  297. drawHelper.StartClipping( rcEventArea );
  298. if ( m_bHasAudio )
  299. {
  300. RenderCloseCaptionExpandCollapseRect( drawHelper, rcEventArea );
  301. if ( m_pView->GetShowCloseCaptionData() )
  302. {
  303. RenderCloseCaptionExpandCollapseRect( drawHelper, rcEventArea );
  304. RenderCloseCaptionInfo( drawHelper, rcEventArea );
  305. RenderCloseCaptions( drawHelper, rcEventArea );
  306. RenderCloseCaptionSelectors( drawHelper, rcEventArea );
  307. }
  308. }
  309. for ( int j = GetNumEvents()-1; j >= 0; j-- )
  310. {
  311. CChoreoEventWidget *event = GetEvent( j );
  312. if ( event )
  313. {
  314. event->redraw( drawHelper );
  315. }
  316. }
  317. drawHelper.StopClipping();
  318. }
  319. //-----------------------------------------------------------------------------
  320. // Purpose:
  321. // Input : drawHelper -
  322. // rcEventArea -
  323. //-----------------------------------------------------------------------------
  324. void CChoreoChannelWidget::RenderCloseCaptionInfo( CChoreoWidgetDrawHelper& drawHelper, RECT& rcEventArea )
  325. {
  326. wchar_t wstr[ 1024 ];
  327. COLORREF barColor = RGB( 100, 200, 255 );
  328. {
  329. RECT rcText = rcEventArea;
  330. rcText.left += 2;
  331. rcText.top = rcEventArea.bottom - 15;
  332. rcText.bottom = rcText.top + 12;
  333. drawHelper.DrawColoredText( "Arial", m_pView->GetFontSize() - 2, 500,
  334. COLOR_CHOREO_TEXT, rcText, "token/data:" );
  335. }
  336. // Walk the events looking for SPEAK events (esp if marked as MASTER with >= 1 slave)
  337. for ( int j = GetNumEvents()-1; j >= 0; j-- )
  338. {
  339. CChoreoEventWidget *event = GetEvent( j );
  340. CChoreoEvent *e = event->GetEvent();
  341. if ( e->GetType() != CChoreoEvent::SPEAK )
  342. continue;
  343. if ( e->GetCloseCaptionType() == CChoreoEvent::CC_SLAVE )
  344. continue;
  345. char const *label = "";
  346. bool showState = false;
  347. bool stateValid = false;
  348. if ( e->GetCloseCaptionType() == CChoreoEvent::CC_MASTER )
  349. {
  350. showState = true;
  351. if ( e->GetNumSlaves() >= 1 )
  352. {
  353. barColor = RGB( 100, 200, 255 );
  354. label = e->GetCloseCaptionToken();
  355. }
  356. else
  357. {
  358. barColor = RGB( 100, 150, 100 );
  359. label = e->GetParameters();
  360. }
  361. char cctoken[ CChoreoEvent::MAX_CCTOKEN_STRING ];
  362. if ( e->GetPlaybackCloseCaptionToken( cctoken, sizeof( cctoken ) ) )
  363. {
  364. stateValid = closecaptionmanager->LookupUnicodeText( GetCloseCaptionLanguageId(), cctoken, wstr, sizeof( wstr ) / sizeof( wchar_t ) );
  365. }
  366. }
  367. else
  368. {
  369. barColor = RGB( 150, 150, 150 );
  370. label = "-disabled-";
  371. }
  372. // Found one!!!
  373. RECT rcEvent = event->getBounds();
  374. float bestEndTime = max( e->GetEndTime(), e->GetLastSlaveEndTime() );
  375. int pixeloffset = (int)( ( bestEndTime - e->GetStartTime() ) * m_pView->GetPixelsPerSecond() + 0.5f );
  376. rcEvent.right = rcEvent.left + pixeloffset;
  377. rcEvent.top = rcEventArea.bottom - 3;
  378. rcEvent.bottom = rcEventArea.bottom;
  379. drawHelper.DrawFilledRect( barColor, rcEvent );
  380. RECT rcTriangle;
  381. rcTriangle = rcEvent;
  382. rcTriangle.right = rcTriangle.left + 3;
  383. rcTriangle.left -= 3;
  384. OffsetRect( &rcTriangle, 0, -6 );
  385. rcTriangle.bottom += 6;
  386. drawHelper.DrawTriangleMarker( rcTriangle, barColor, true );
  387. rcTriangle.left = rcEvent.right - 3;
  388. rcTriangle.right = rcEvent.right + 3;
  389. drawHelper.DrawTriangleMarker( rcTriangle, barColor, true );
  390. RECT rcText = rcEvent;
  391. rcText.bottom = rcText.top + 12;
  392. OffsetRect( &rcText, 5, -12 );
  393. if ( showState )
  394. {
  395. int stateMarkWidth = 12;
  396. RECT rcState = rcText;
  397. rcState.right = rcState.left + stateMarkWidth;
  398. rcText.left += stateMarkWidth;
  399. COLORREF symColor = stateValid ? RGB( 40, 100, 40 ) : RGB( 200, 40, 40 );
  400. drawHelper.DrawColoredTextCharset(
  401. "Marlett",
  402. m_pView->GetFontSize() - 2,
  403. 500,
  404. SYMBOL_CHARSET,
  405. symColor,
  406. rcState,
  407. stateValid ? "a" : "r" );
  408. }
  409. if ( e->IsSuppressingCaptionAttenuation() )
  410. {
  411. drawHelper.DrawColoredText( "Arial", m_pView->GetFontSize() - 2, 500,
  412. RGB( 80, 80, 100 ), rcText, "%s [no attenuate]", label );
  413. }
  414. else
  415. {
  416. drawHelper.DrawColoredText( "Arial", m_pView->GetFontSize() - 2, 500,
  417. RGB( 80, 80, 100 ), rcText, label );
  418. }
  419. }
  420. }
  421. //-----------------------------------------------------------------------------
  422. // Purpose:
  423. // Input : drawHelper -
  424. // rcEventArea -
  425. //-----------------------------------------------------------------------------
  426. void CChoreoChannelWidget::RenderCloseCaptions( CChoreoWidgetDrawHelper& drawHelper, RECT& rcEventArea )
  427. {
  428. {
  429. RECT rcText = rcEventArea;
  430. rcText.top = rcEventArea.top + m_nBaseHeight + AUDIO_HEIGHT + 5;
  431. rcText.bottom = rcText.top + 12;
  432. rcText.left += 12;
  433. drawHelper.DrawColoredText( "Arial", m_pView->GetFontSize() - 2, 500,
  434. COLOR_CHOREO_TEXT, rcText, "%s", CSentence::NameForLanguage( GetCloseCaptionLanguageId() ) );
  435. // Previous
  436. GetCloseCaptionLanguageRect( rcText, true );
  437. drawHelper.DrawColoredTextCharset(
  438. "Marlett",
  439. m_pView->GetFontSize(),
  440. 500,
  441. SYMBOL_CHARSET,
  442. COLOR_CHOREO_TEXT,
  443. rcText,
  444. "3" );
  445. // Next
  446. GetCloseCaptionLanguageRect( rcText, false );
  447. drawHelper.DrawColoredTextCharset(
  448. "Marlett",
  449. m_pView->GetFontSize(),
  450. 500,
  451. SYMBOL_CHARSET,
  452. COLOR_CHOREO_TEXT,
  453. rcText,
  454. "4" );
  455. }
  456. // Walk the events looking for SPEAK events (esp if marked as MASTER with >= 1 slave)
  457. for ( int j = GetNumEvents()-1; j >= 0; j-- )
  458. {
  459. CChoreoEventWidget *event = GetEvent( j );
  460. CChoreoEvent *e = event->GetEvent();
  461. if ( e->GetType() != CChoreoEvent::SPEAK )
  462. continue;
  463. if ( e->GetCloseCaptionType() == CChoreoEvent::CC_SLAVE ||
  464. e->GetCloseCaptionType() == CChoreoEvent::CC_DISABLED )
  465. continue;
  466. char cctoken[ CChoreoEvent::MAX_CCTOKEN_STRING ];
  467. bool valid = e->GetPlaybackCloseCaptionToken( cctoken, sizeof( cctoken ) );
  468. if ( !valid )
  469. continue;
  470. wchar_t wstr[ 1024 ];
  471. valid = closecaptionmanager->LookupStrippedUnicodeText( GetCloseCaptionLanguageId(), cctoken, wstr, sizeof( wstr ) / sizeof( wchar_t ) );
  472. // Found one!!!
  473. RECT rcEvent = event->getBounds();
  474. float bestEndTime = max( e->GetEndTime(), e->GetLastSlaveEndTime() );
  475. int pixeloffset = (int)( ( bestEndTime - e->GetStartTime() ) * m_pView->GetPixelsPerSecond() + 0.5f );
  476. rcEvent.right = rcEvent.left + pixeloffset;
  477. rcEvent.top = rcEventArea.top + m_nBaseHeight + AUDIO_HEIGHT + 5;
  478. rcEvent.bottom = rcEvent.top + 12;
  479. rcEvent.left += 5;
  480. COLORREF textColor = valid ? RGB( 80, 80, 100 ) : RGB( 225, 40, 40 );
  481. drawHelper.DrawColoredTextW( STREAM_FONT, m_pView->GetFontSize() - 2, 500,
  482. textColor, rcEvent, wstr );
  483. }
  484. }
  485. //-----------------------------------------------------------------------------
  486. // Purpose:
  487. // Output : CChoreoChannel
  488. //-----------------------------------------------------------------------------
  489. CChoreoChannel *CChoreoChannelWidget::GetChannel( void )
  490. {
  491. return m_pChannel;
  492. }
  493. //-----------------------------------------------------------------------------
  494. // Purpose:
  495. // Input : *channel -
  496. //-----------------------------------------------------------------------------
  497. void CChoreoChannelWidget::SetChannel( CChoreoChannel *channel )
  498. {
  499. m_pChannel = channel;
  500. }
  501. //-----------------------------------------------------------------------------
  502. // Purpose:
  503. // Input : *event -
  504. //-----------------------------------------------------------------------------
  505. void CChoreoChannelWidget::AddEvent( CChoreoEventWidget *event )
  506. {
  507. m_Events.AddToTail( event );
  508. }
  509. //-----------------------------------------------------------------------------
  510. // Purpose:
  511. // Input : *event -
  512. //-----------------------------------------------------------------------------
  513. void CChoreoChannelWidget::RemoveEvent( CChoreoEventWidget *event )
  514. {
  515. m_Events.FindAndRemove( event );
  516. }
  517. //-----------------------------------------------------------------------------
  518. // Purpose:
  519. // Input : num -
  520. // Output : CChoreoEventWidget
  521. //-----------------------------------------------------------------------------
  522. CChoreoEventWidget *CChoreoChannelWidget::GetEvent( int num )
  523. {
  524. return m_Events[ num ];
  525. }
  526. //-----------------------------------------------------------------------------
  527. // Purpose:
  528. // Output : int
  529. //-----------------------------------------------------------------------------
  530. int CChoreoChannelWidget::GetNumEvents( void )
  531. {
  532. return m_Events.Size();
  533. }
  534. //-----------------------------------------------------------------------------
  535. // Purpose:
  536. // Input : *event -
  537. //-----------------------------------------------------------------------------
  538. void CChoreoChannelWidget::MoveEventToTail( CChoreoEventWidget *event )
  539. {
  540. for ( int i = 0; i < GetNumEvents(); i++ )
  541. {
  542. CChoreoEventWidget *ew = GetEvent( i );
  543. if ( ew == event )
  544. {
  545. m_Events.Remove( i );
  546. m_Events.AddToTail( ew );
  547. break;
  548. }
  549. }
  550. }
  551. int CChoreoChannelWidget::GetChannelItemUnderMouse( int mx, int my )
  552. {
  553. m_nSelectorEventIndex = -1;
  554. if ( !m_bHasAudio )
  555. return CLOSECAPTION_NONE;
  556. RECT rcCCArea;
  557. GetCloseCaptionExpandCollapseRect( rcCCArea );
  558. POINT pt;
  559. pt.x = mx;
  560. pt.y = my;
  561. if ( PtInRect( &rcCCArea, pt ) )
  562. {
  563. return CLOSECAPTION_EXPANDCOLLAPSE;
  564. }
  565. // previous
  566. GetCloseCaptionLanguageRect( rcCCArea, true );
  567. if ( PtInRect( &rcCCArea, pt ) )
  568. {
  569. return CLOSECAPTION_PREVLANGUAGE;
  570. }
  571. // next language
  572. GetCloseCaptionLanguageRect( rcCCArea, false );
  573. if ( PtInRect( &rcCCArea, pt ) )
  574. {
  575. return CLOSECAPTION_NEXTLANGUAGE;
  576. }
  577. CUtlVector< CloseCaptionInfo > vecSelectors;
  578. GetCloseCaptions( vecSelectors );
  579. int c = vecSelectors.Count();
  580. if ( vecSelectors.Count() > 0 )
  581. {
  582. int i;
  583. for ( i = 0; i < c; ++i )
  584. {
  585. CloseCaptionInfo& check = vecSelectors[ i ];
  586. if ( check.isSelector && PtInRect( &check.rcSelector, pt ) )
  587. {
  588. m_nSelectorEventIndex = check.eventindex;
  589. return CLOSECAPTION_SELECTOR;
  590. }
  591. }
  592. for ( i = 0; i < c; ++i )
  593. {
  594. CloseCaptionInfo& check = vecSelectors[ i ];
  595. if ( PtInRect( &check.rcCaption, pt ) )
  596. {
  597. m_nSelectorEventIndex = check.eventindex;
  598. return CLOSECAPTION_CAPTION;
  599. }
  600. }
  601. }
  602. return CLOSECAPTION_NONE;
  603. }
  604. //-----------------------------------------------------------------------------
  605. // Purpose:
  606. //-----------------------------------------------------------------------------
  607. void CChoreoChannelWidget::HandleSelectorClicked()
  608. {
  609. if ( m_nSelectorEventIndex < 0 )
  610. return;
  611. if ( m_nSelectorEventIndex >= m_Events.Count() )
  612. return;
  613. CChoreoEvent *event = GetEvent( m_nSelectorEventIndex )->GetEvent();
  614. SetUsingCombinedFieldByTokenName( event->GetCloseCaptionToken(), !event->IsUsingCombinedFile() );
  615. }
  616. void CChoreoChannelWidget::SetUsingCombinedFieldByTokenName( char const *token, bool usingcombinedfile )
  617. {
  618. int c = GetNumEvents();
  619. for ( int i = 0; i < c; ++i )
  620. {
  621. CChoreoEvent *e = GetEvent( i )->GetEvent();
  622. if ( !Q_stricmp( e->GetCloseCaptionToken(), token ) )
  623. {
  624. e->SetUsingCombinedFile( usingcombinedfile );
  625. }
  626. }
  627. }
  628. //-----------------------------------------------------------------------------
  629. // Purpose:
  630. // Output : CChoreoEvent
  631. //-----------------------------------------------------------------------------
  632. CChoreoEvent *CChoreoChannelWidget::GetCaptionClickedEvent()
  633. {
  634. if ( m_nSelectorEventIndex < 0 )
  635. return NULL;
  636. if ( m_nSelectorEventIndex >= m_Events.Count() )
  637. return NULL;
  638. CChoreoEvent *event = GetEvent( m_nSelectorEventIndex )->GetEvent();
  639. return event;
  640. }
  641. void CChoreoChannelWidget::GetCloseCaptionExpandCollapseRect( RECT& rc )
  642. {
  643. Assert( m_bHasAudio );
  644. rc = getBounds();
  645. rc.left = m_pView->GetLabelWidth() + 2;
  646. rc.right = rc.left + 12;
  647. rc.top += 2;
  648. rc.bottom = rc.top + 12;
  649. }
  650. void CChoreoChannelWidget::GetCloseCaptionLanguageRect( RECT& rc, bool previous )
  651. {
  652. Assert( m_bHasAudio );
  653. RECT rcEventArea = getBounds();
  654. rcEventArea.left = m_pView->GetLabelWidth() + 1;
  655. rcEventArea.top -= 20;
  656. rc = rcEventArea;
  657. rc.top = rcEventArea.top + m_nBaseHeight + AUDIO_HEIGHT + 5;
  658. rc.bottom = rc.top + 12;
  659. rc.left += 2;
  660. rc.right = rc.left + 12;
  661. if ( !previous )
  662. {
  663. int textlen = CChoreoWidgetDrawHelper::CalcTextWidth
  664. (
  665. "Arial",
  666. m_pView->GetFontSize()-2,
  667. 500,
  668. CSentence::NameForLanguage( GetCloseCaptionLanguageId() )
  669. );
  670. OffsetRect( &rc, textlen + 10, 0 );
  671. }
  672. }
  673. void CChoreoChannelWidget::RenderCloseCaptionSelectors( CChoreoWidgetDrawHelper& drawHelper, RECT& rcEventArea )
  674. {
  675. CUtlVector< CloseCaptionInfo > vecSelectors;
  676. GetCloseCaptions( vecSelectors );
  677. int c = vecSelectors.Count();
  678. if ( vecSelectors.Count() > 0 )
  679. {
  680. for ( int i = 0; i < c; ++i )
  681. {
  682. CloseCaptionInfo& check = vecSelectors[ i ];
  683. if ( !check.isSelector )
  684. continue;
  685. CChoreoEventWidget *e = GetEvent( check.eventindex );
  686. if ( !e )
  687. continue;
  688. CChoreoEvent *event = e->GetEvent();
  689. bool upArrow = !event->IsUsingCombinedFile();
  690. COLORREF clr = RGB( 63, 63, 63 ); // upArrow ? RGB( 255, 0, 0 ) : RGB( 0, 0, 255 );
  691. RECT rc = check.rcSelector;
  692. POINT endpt;
  693. endpt.x = rc.right - 2;
  694. if ( upArrow )
  695. {
  696. endpt.y = rc.top - 9;
  697. }
  698. else
  699. {
  700. endpt.y = rc.bottom + 9;
  701. }
  702. POINT startpt;
  703. startpt.x = ( rc.left + rc.right ) * 0.5;
  704. startpt.y = ( rc.top + rc.bottom ) * 0.5;
  705. drawHelper.DrawCircle(
  706. clr,
  707. endpt.x,
  708. endpt.y,
  709. 3 , true );
  710. drawHelper.DrawColoredLine( clr, PS_SOLID, 1, startpt.x, startpt.y, endpt.x, endpt.y );
  711. drawHelper.DrawCircle(
  712. clr,
  713. startpt.x,
  714. startpt.y,
  715. 7, true );
  716. }
  717. }
  718. }
  719. void CChoreoChannelWidget::GetCloseCaptions( CUtlVector< CloseCaptionInfo >& selectors )
  720. {
  721. selectors.RemoveAll();
  722. // Walk the events looking for SPEAK events (esp if marked as MASTER with >= 1 slave)
  723. for ( int j = GetNumEvents()-1; j >= 0; j-- )
  724. {
  725. CChoreoEventWidget *event = GetEvent( j );
  726. CChoreoEvent *e = event->GetEvent();
  727. if ( e->GetType() != CChoreoEvent::SPEAK )
  728. continue;
  729. CChoreoEvent::CLOSECAPTION capType = e->GetCloseCaptionType();
  730. if ( capType == CChoreoEvent::CC_SLAVE )
  731. continue;
  732. bool isSelector = ( e->GetNumSlaves() >= 1 ) && capType == CChoreoEvent::CC_MASTER;
  733. // Found one!!!
  734. RECT rcEvent = event->getBounds();
  735. RECT rcCaption = rcEvent;
  736. rcEvent.right = rcEvent.left + 16;
  737. OffsetRect( &rcEvent, -16, rcEvent.bottom - rcEvent.top );
  738. rcEvent.bottom = rcEvent.top + 16;
  739. CloseCaptionInfo ccs;
  740. ccs.rcSelector = rcEvent;
  741. ccs.isSelector = isSelector;
  742. rcCaption.top += rcEvent.bottom - rcEvent.top;
  743. RECT rcEventArea = getBounds();
  744. rcCaption.bottom = rcEventArea.bottom;
  745. // Now compute true right edge
  746. float bestEndTime = max( e->GetEndTime(), e->GetLastSlaveEndTime() );
  747. int pixeloffset = (int)( ( bestEndTime - e->GetStartTime() ) * m_pView->GetPixelsPerSecond() + 0.5f );
  748. rcCaption.right = rcCaption.left + pixeloffset;
  749. ccs.rcCaption = rcCaption;
  750. ccs.eventindex = j;
  751. selectors.AddToTail( ccs );
  752. }
  753. }
  754. void CChoreoChannelWidget::RenderCloseCaptionExpandCollapseRect( CChoreoWidgetDrawHelper& drawHelper, RECT& rcEventArea )
  755. {
  756. if ( !m_bHasAudio )
  757. return;
  758. RECT rcCCArea;
  759. GetCloseCaptionExpandCollapseRect( rcCCArea );
  760. COLORREF symColor = RGB( 100, 100, 100 );
  761. drawHelper.DrawColoredTextCharset(
  762. "Marlett",
  763. m_pView->GetFontSize(),
  764. 900,
  765. SYMBOL_CHARSET,
  766. symColor,
  767. rcCCArea,
  768. m_pView->GetShowCloseCaptionData() ? "6" : "4" );
  769. }
  770. void CChoreoChannelWidget::GetMasterAndSlaves( CChoreoEvent *master, CUtlVector< CChoreoEvent * >& fulllist )
  771. {
  772. // Old
  773. int c = GetNumEvents();
  774. int i;
  775. for ( i = 0; i < c; ++i )
  776. {
  777. CChoreoEvent *e = GetEvent( i )->GetEvent();
  778. if ( !Q_stricmp( master->GetCloseCaptionToken(), e->GetCloseCaptionToken() ) )
  779. {
  780. if ( fulllist.Find( e ) == fulllist.InvalidIndex() )
  781. {
  782. fulllist.AddToTail( e );
  783. }
  784. }
  785. }
  786. }
  787. //-----------------------------------------------------------------------------
  788. // Purpose:
  789. // Input : drawHelper -
  790. // rcBounds -
  791. //-----------------------------------------------------------------------------
  792. void CChoreoChannelWidget::redrawStatus( CChoreoWidgetDrawHelper& drawHelper, RECT& rcClient, int areaUnderMouse )
  793. {
  794. if ( !getVisible() )
  795. return;
  796. if ( areaUnderMouse != CLOSECAPTION_CAPTION )
  797. return;
  798. CChoreoEvent *e = GetCaptionClickedEvent();
  799. if ( !e )
  800. return;
  801. int deflateborder = 1;
  802. int fontsize = 9;
  803. // Now draw the label
  804. RECT rcEventLabel;
  805. rcEventLabel = rcClient;
  806. InflateRect( &rcEventLabel, 0, -deflateborder );
  807. // rcEventLabel.top += 2;
  808. rcEventLabel.left += 2;
  809. //rcEventLabel.top = rcEventLabel.bottom - 2 * ( fontsize + 2 ) - 1;
  810. //rcEventLabel.bottom = rcEventLabel.top + fontsize + 2;
  811. /*
  812. HDC dc = drawHelper.GrabDC();
  813. int leftAdd = 16;
  814. if ( CChoreoEventWidget::GetImage( event->GetType() ) )
  815. {
  816. mxbitmapdata_t *image = CChoreoEventWidget::GetImage( event->GetType() );
  817. if ( image )
  818. {
  819. RECT rcFixed = rcEventLabel;
  820. drawHelper.OffsetSubRect( rcFixed );
  821. DrawBitmapToDC( dc, rcFixed.left, rcFixed.top, leftAdd, leftAdd,
  822. *image );
  823. }
  824. }
  825. // Draw Type Name:
  826. //rcEventLabel.top -= 4;
  827. rcEventLabel.left = rcClient.left + 32;
  828. rcEventLabel.bottom = rcEventLabel.top + fontsize + 2;
  829. // OffsetRect( &rcEventLabel, 0, 2 );
  830. int len = drawHelper.CalcTextWidth( "Arial", fontsize, FW_NORMAL, "%s event \"%s\"",
  831. event->NameForType( event->GetType() ), event->GetName() );
  832. drawHelper.DrawColoredText( "Arial", fontsize, FW_NORMAL, COLOR_INFO_TEXT, rcEventLabel, "%s event \"%s\"",
  833. event->NameForType( event->GetType() ), event->GetName() );
  834. OffsetRect( &rcEventLabel, 0, fontsize + 2 );
  835. drawHelper.DrawColoredText( "Arial", fontsize, FW_NORMAL, COLOR_INFO_TEXT,
  836. rcEventLabel, "parameters \"%s\"", GetLabelText() );
  837. */
  838. char const *label = "";
  839. bool showState = false;
  840. bool stateValid = false;
  841. wchar_t wstr[ 1024 ];
  842. COLORREF labelColor = COLOR_INFO_TEXT;
  843. if ( e->GetCloseCaptionType() == CChoreoEvent::CC_MASTER )
  844. {
  845. showState = true;
  846. if ( e->GetNumSlaves() >= 1 )
  847. {
  848. label = e->GetCloseCaptionToken();
  849. }
  850. else
  851. {
  852. label = e->GetParameters();
  853. }
  854. }
  855. else if ( e->GetCloseCaptionType() == CChoreoEvent::CC_SLAVE )
  856. {
  857. showState = true;
  858. label = e->GetCloseCaptionToken();
  859. }
  860. else
  861. {
  862. label = "-disabled-";
  863. }
  864. char cctoken[ CChoreoEvent::MAX_CCTOKEN_STRING ];
  865. if ( showState && e->GetPlaybackCloseCaptionToken( cctoken, sizeof( cctoken ) ) )
  866. {
  867. stateValid = closecaptionmanager->LookupUnicodeText( GetCloseCaptionLanguageId(), cctoken, wstr, sizeof( wstr ) / sizeof( wchar_t ) );
  868. }
  869. RECT rcText = rcEventLabel;
  870. rcText.left += 250;
  871. rcText.bottom = rcText.top + fontsize + 1;
  872. if ( showState )
  873. {
  874. int stateMarkWidth = 12;
  875. RECT rcState = rcText;
  876. rcState.right = rcState.left + stateMarkWidth;
  877. rcText.left += stateMarkWidth;
  878. COLORREF symColor = stateValid ? RGB( 40, 100, 40 ) : RGB( 200, 40, 40 );
  879. drawHelper.DrawColoredTextCharset(
  880. "Marlett",
  881. fontsize+2,
  882. 500,
  883. SYMBOL_CHARSET,
  884. symColor,
  885. rcState,
  886. stateValid ? "a" : "r" );
  887. }
  888. drawHelper.DrawColoredText( "Arial", fontsize, 500,
  889. labelColor, rcText, "closecaption token: %s", label );
  890. RECT saveText = rcText;
  891. COLORREF statusClr = RGB( 20, 150, 20 );
  892. if ( e->GetCloseCaptionType() != CChoreoEvent::CC_DISABLED )
  893. {
  894. if ( e->GetNumSlaves() >= 1 ||
  895. e->GetCloseCaptionType() == CChoreoEvent::CC_SLAVE )
  896. {
  897. bool combinedValid = m_pView->ValidateCombinedSoundCheckSum( e );
  898. OffsetRect( &rcText, 0, fontsize + 3 );
  899. char cf[ 256 ];
  900. Q_strncpy( cf, "(no file)", sizeof( cf ) );
  901. // Get the filename, including expansion for gender
  902. e->ComputeCombinedBaseFileName( cf, sizeof( cf ), e->IsCombinedUsingGenderToken() );
  903. bool gendermacro = Q_stristr( cf, SOUNDGENDER_MACRO ) ? true : false;
  904. char exist[ 256 ];
  905. if ( gendermacro )
  906. {
  907. bool valid[2];
  908. char actualfile[ 256 ];
  909. soundemitter->GenderExpandString( GENDER_MALE, cf, actualfile, sizeof( actualfile ) );
  910. valid[ 0 ] = filesystem->FileExists( actualfile );
  911. soundemitter->GenderExpandString( GENDER_FEMALE, cf, actualfile, sizeof( actualfile ) );
  912. valid[ 1 ] = filesystem->FileExists( actualfile );
  913. if ( !valid[ 0 ] || !valid[ 1 ] )
  914. {
  915. statusClr = RGB( 255, 0, 0 );
  916. }
  917. Q_snprintf( exist, sizeof( exist ), "%s", valid ? "exist" : "missing!" );
  918. }
  919. else
  920. {
  921. bool valid = filesystem->FileExists( cf );
  922. if ( !valid )
  923. {
  924. statusClr = RGB( 255, 0, 0 );
  925. }
  926. Q_snprintf( exist, sizeof( exist ), "%s", valid ? "exists" : "missing!" );
  927. }
  928. RECT rcPartial = rcText;
  929. char sz[ 256 ];
  930. Q_snprintf( sz, sizeof( sz ),
  931. "combined file active [ %s ] gender[ %s ] up-to-date[ ",
  932. e->IsUsingCombinedFile() ? "yes" : "no",
  933. e->IsCombinedUsingGenderToken() ? "yes" : "no" );
  934. int len = drawHelper.CalcTextWidth( "Arial", fontsize, 500, sz );
  935. drawHelper.DrawColoredText( "Arial", fontsize, 500,
  936. labelColor, rcPartial, sz );
  937. rcPartial.left += len;
  938. Q_snprintf( sz, sizeof( sz ),
  939. "%s",
  940. combinedValid ? "yes" : "no" );
  941. len = drawHelper.CalcTextWidth( "Arial", fontsize, 500, sz );
  942. drawHelper.DrawColoredText( "Arial", fontsize, 500,
  943. combinedValid ? RGB( 20, 150, 20 ) : RGB( 255, 0, 0 ),
  944. rcPartial, sz );
  945. rcPartial.left += len;
  946. Q_snprintf( sz, sizeof( sz ),
  947. " ]: %s, %s ",
  948. cf,
  949. gendermacro ? "files" : "file" );
  950. len = drawHelper.CalcTextWidth( "Arial", fontsize, 500, sz );
  951. drawHelper.DrawColoredText( "Arial", fontsize, 500,
  952. labelColor, rcPartial, sz );
  953. rcPartial.left += len;
  954. drawHelper.DrawColoredText( "Arial", fontsize, 500,
  955. statusClr, rcPartial, exist );
  956. }
  957. rcText = saveText;
  958. OffsetRect( &rcText, 400, 0 );
  959. // Print out script file for sound
  960. int soundindex = soundemitter->GetSoundIndex( cctoken );
  961. if ( soundindex >= 0 )
  962. {
  963. char const *scriptfile = soundemitter->GetSourceFileForSound( soundindex );
  964. Assert( scriptfile );
  965. if ( scriptfile )
  966. {
  967. drawHelper.DrawColoredText( "Arial", fontsize, 500,
  968. labelColor, rcText, "sound script: %s", scriptfile );
  969. }
  970. }
  971. else
  972. {
  973. drawHelper.DrawColoredText( "Arial", fontsize, 500,
  974. RGB( 255, 0, 0 ), rcText, "sound not in game_sounds script files!" );
  975. }
  976. }
  977. }