⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 phonemeeditor_closecaption.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
}

void PhonemeEditor::CloseCaption_CleanupPhrases( bool prepareundo )
{
	if ( GetMode() != MODE_CLOSECAPTION )
		return;

	// 2 pixel gap
	float snap_epsilon = 2.49f / GetPixelsPerSecond();

	if ( prepareundo )
	{
		SetDirty( true );
		PushUndo();
	}

	CloseCaption_SortPhrases( false );

	for ( int i = 0 ; i < m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ) ; i++ )
	{
		CCloseCaptionPhrase *phrase = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i );
		if ( !phrase )
			continue;

		CCloseCaptionPhrase *next = NULL;
		if ( i < m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ) - 1 )
		{
			next = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i + 1 );
		}

		if ( phrase && next )
		{
			// Check for phrases close enough
			float eps = next->GetStartTime() - phrase->GetEndTime();
			if ( eps && eps <= snap_epsilon )
			{
				float t = (phrase->GetEndTime() + next->GetStartTime()) * 0.5;
				phrase->SetEndTime( t );
				next->SetStartTime( t );
			}
		}

		float dt = phrase->GetEndTime() - phrase->GetStartTime();
		if ( dt <= 0.01 )
		{
			phrase->SetEndTime( phrase->GetStartTime() + DEFAULT_PHRASE_LENGTH );
		}
	}

	if ( prepareundo )
	{
		PushRedo();
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : index - 
//-----------------------------------------------------------------------------
void PhonemeEditor::CloseCaption_SetClickedPhrase( int index, int token )
{
	m_nClickedPhrase = index;
	m_nClickedPhraseToken = token;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : CCloseCaptionPhrase	*phrase - 
// Output : int
//-----------------------------------------------------------------------------
int PhonemeEditor::CloseCaption_IndexOfPhrase( CCloseCaptionPhrase *phrase )
{
	return m_Tags.FindCloseCaptionPhraseIndex( CC_ENGLISH, phrase );
}

void PhonemeEditor::TraversePhrases( PEPHRASEITERFUNC pfn, float fparam )
{
	int c = m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH );

	for ( int i = 0; i < c; i++ )
	{
		CCloseCaptionPhrase *phrase = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i );
		if ( !phrase )
			continue;

		(this->*pfn)( phrase, fparam );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : amount - 
//-----------------------------------------------------------------------------
void PhonemeEditor::ITER_MoveSelectedPhrases( CCloseCaptionPhrase *phrase, float amount )
{
	if ( !phrase->GetSelected() )
		return;

	phrase->SetStartTime( phrase->GetStartTime() + amount );
	phrase->SetEndTime( phrase->GetEndTime() + amount );
}

void PhonemeEditor::ITER_ExtendSelectedPhraseEndTimes( CCloseCaptionPhrase *phrase, float amount )
{
	if ( !phrase->GetSelected() )
		return;

	if ( phrase->GetEndTime() + amount <= phrase->GetStartTime() )
		return;

	phrase->SetEndTime( phrase->GetEndTime() + amount );
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : drawHelper - 
//			rcWorkSpace - 
//-----------------------------------------------------------------------------
void PhonemeEditor::CloseCaption_Redraw( CChoreoWidgetDrawHelper& drawHelper, RECT& rcWorkSpace, CSentence& sentence )
{
	if ( GetMode() != MODE_CLOSECAPTION )
		return;

	float starttime = m_nLeftOffset / GetPixelsPerSecond();
	float endtime = w2() / GetPixelsPerSecond() + starttime;

	RECT rcCC;
	CloseCaption_GetTrayTopBottom( rcCC );

	int ypos = rcCC.top;

	const char *fontName = "Arial Unicode MS";

	RECT rcTitle = rcCC;
	OffsetRect( &rcTitle, 0, -20 );
	rcTitle.left = 15;
	rcTitle.right = w2();

	drawHelper.DrawColoredText( "Arial", 15, FW_BOLD, PEColor( COLOR_PHONEME_CC_TEXT ), rcTitle,
		"Close caption..." );

	drawHelper.DrawColoredLine( PEColor( COLOR_PHONEME_CC_TAG_FILLER_NORMAL ), PS_SOLID, 1,
		0, rcCC.top-1, w2(), rcCC.top-1 );
	drawHelper.DrawColoredLine( PEColor( COLOR_PHONEME_CC_TAG_FILLER_NORMAL ), PS_SOLID, 1,
		0, rcCC.bottom, w2(), rcCC.bottom );
	

	bool drawselected;
	for ( int pass = 0; pass < 2 ; pass++ )
	{
		drawselected = pass == 0 ? false : true;

		int count = sentence.GetCloseCaptionPhraseCount( CC_ENGLISH );
		for (int k = 0; k < count; k++)
		{
			CCloseCaptionPhrase *phrase = sentence.GetCloseCaptionPhrase( CC_ENGLISH, k );
			if ( !phrase )
				continue;

			if ( phrase->GetSelected() != drawselected )
				continue;

			float t1 = phrase->GetStartTime();
			float t2 = phrase->GetEndTime();

			// Tag it
			float frac = ( t1 - starttime ) / ( endtime - starttime );

			int xpos = ( int )( frac * rcWorkSpace.right );

			//if ( frac <= 0.0 )
			//	xpos = 0;

			// Draw duration
			float frac2  = ( t2 - starttime ) / ( endtime - starttime );
			if ( frac2 < 0.0 )
				continue;

			int xpos2 = ( int )( frac2 * rcWorkSpace.right );

			// Draw line and vertical ticks
			RECT rcPhrase;
			CloseCaption_GetPhraseRect( phrase, rcPhrase );

			/*
			rcPhrase.left = xpos;
			rcPhrase.right = xpos2;
			rcPhrase.top = ypos;
			rcPhrase.bottom = ypos + m_nTickHeight - 1;
			*/

			drawHelper.DrawFilledRect( 
				PEColor( phrase->GetSelected() ? COLOR_PHONEME_CC_TAG_SELECTED : COLOR_PHONEME_CC_TAG_FILLER_NORMAL ), 
				rcPhrase );

			COLORREF border = PEColor( phrase->GetSelected() ? COLOR_PHONEME_CC_TAG_BORDER_SELECTED : COLOR_PHONEME_CC_TAG_BORDER );

			drawHelper.DrawOutlinedRect( border, PS_SOLID, 1, rcPhrase );

			//if ( frac >= 0.0 && frac <= 1.0 )
			{
				int fontsize = 9;

				RECT rcText;
				rcText.left = xpos;
				rcText.right = xpos2;
				rcText.top = rcCC.top;
				rcText.bottom = rcCC.bottom;

				int availw = xpos2 - xpos;

				int tokenCount = phrase->CountTokens();
				if ( tokenCount >= 1 )
				{
					int pixelsPerToken = availw / tokenCount;

					rcText.right = rcText.left + pixelsPerToken;
					
					for ( int i = 0; i < tokenCount; i++ )
					{
						wchar_t const *token = phrase->GetToken( i );
						if ( token && token[ 0 ] )
						{
							int texw = drawHelper.CalcTextWidthW( fontName,
								fontsize,
								FW_NORMAL,
								L"%s", token );

							RECT rcOutput = rcText;

							if ( texw < pixelsPerToken )
							{
								rcOutput.left += ( pixelsPerToken - texw ) / 2;
							}

							if ( i != tokenCount - 1 )
							{
								// Draw  divider
								drawHelper.DrawColoredLine( border, PS_SOLID, 1,
									rcText.right, rcText.top + 5, rcText.right, rcText.bottom - 5 );
							}

							drawHelper.DrawColoredTextW( 
								fontName, 
								fontsize, 
								FW_NORMAL, 
								PEColor( phrase->GetSelected() ? COLOR_PHONEME_CC_TAG_TEXT_SELECTED : COLOR_PHONEME_CC_TAG_TEXT ), 
								rcOutput,
								L"%s", token );
						}

						OffsetRect( &rcText, pixelsPerToken, 0 );
					}
				}
			}
		}
	}

	RECT rcOutput;
	CloseCaption_GetCCAreaRect( rcOutput );
	CloseCaption_DrawCCArea( drawHelper, rcOutput );
}

void PhonemeEditor::CloseCaption_GetCCAreaRect( RECT& rcOutput )
{
	GetScrubAreaRect( rcOutput );

	rcOutput.left = w2() - 200;
	rcOutput.right = w2();
	rcOutput.top = rcOutput.bottom + 2;
	rcOutput.bottom = rcOutput.top + 125;
}

void PhonemeEditor::CloseCaption_DrawCCArea( CChoreoWidgetDrawHelper& drawHelper, RECT& rcOutput )
{
	closecaptionmanager->Draw( drawHelper, rcOutput );
}

void PhonemeEditor::ITER_AddFocusRectSelectedPhrases( CCloseCaptionPhrase *phrase, float amount )
{
	if ( !phrase->GetSelected() )
		return;

	RECT phraseRect;
	CloseCaption_GetPhraseRect( phrase, phraseRect );

	AddFocusRect( phraseRect );
}

void PhonemeEditor::CloseCaption_FinishPhraseMove( int startx, int endx )
{
	float clicktime	= GetTimeForPixel( startx );
	float endtime	= GetTimeForPixel( endx );

	// Find the phonemes who have the closest start/endtime to the starting click time
	CCloseCaptionPhrase *current, *next;

	if ( !CloseCaption_FindSpanningPhrases( clicktime, &current, &next ) )
	{
		return;
	}

	SetDirty( true );

	PushUndo();

	if ( current && !next )
	{
		// cap movement
		current->SetEndTime( current->GetEndTime() + ( endtime - clicktime ) );
	}
	else if ( !current && next )
	{
		// cap movement
		next->SetStartTime( next->GetStartTime() + ( endtime - clicktime ) );
	}
	else
	{
		// cap movement
		endtime = min( endtime, next->GetEndTime() - 1.0f / GetPixelsPerSecond() );
		endtime = max( endtime, current->GetStartTime() + 1.0f / GetPixelsPerSecond() );

		current->SetEndTime( endtime );
		next->SetStartTime( endtime );
	}

	CloseCaption_CleanupPhrases( false );

	PushRedo();

	redraw();
}

void PhonemeEditor::CloseCaption_FinishPhraseDrag( int startx, int endx )
{
	float clicktime	= GetTimeForPixel( startx );
	float endtime	= GetTimeForPixel( endx );

	float dt = endtime - clicktime;

	SetDirty( true );

	PushUndo();

	TraversePhrases( ITER_MoveSelectedPhrases, dt );

	CloseCaption_CleanupPhrases( false );

	PushRedo();

	redraw();
}

void PhonemeEditor::CloseCaption_SelectPhrases( void )
{
	if ( GetMode() != MODE_CLOSECAPTION )
		return;

	for ( int i = 0 ; i < m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ); i++ )
	{
		CCloseCaptionPhrase *w = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i );
		Assert( w );
		w->SetSelected( true );
	}

	redraw();
}

void PhonemeEditor::CloseCaption_EditDefaultPhrase( void )
{
	if ( m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ) == 0 )
	{
		SetDirty( true );

		PushUndo();

		m_Tags.SetCloseCaptionFromText( CC_ENGLISH );

		PushRedo();

		redraw();
	}
	else
	{
		Con_Printf( "Can only set default phrase on a sentence without existing phrases\n" );
	}
}



void PhonemeEditor::CloseCaption_SplitPhraseAfterToken( CCloseCaptionPhrase *phrase, int splitToken )
{
	int count = phrase->CountTokens();
	if ( count < 2 )
	{
		Con_Printf( "PhonemeEditor::CloseCaption_SplitPhraseAtToken:  Can't split %s, %i tokens total\n",
			phrase->GetStream(),
			count );
		return;
	}

	if ( splitToken >= count - 1 )
	{
		// After end...sigh
		return;
	}

	wchar_t stream1[ 4096 ];
	wchar_t stream2[ 4096 ];

	stream1[0] = L'\0';
	stream2[0] = L'\0';

	wchar_t const *token;
	int count1 = 0;
	int count2 = 0;

	for ( int i = 0; i < count; i++ )
	{
		token = phrase->GetToken( i );
		Assert( token && token[ 0 ] );
		if ( i <= splitToken )
		{
			if ( count1 != 0 )
			{
				wcscat( stream1, L" " );
			}

			wcscat( stream1, token );
			count1++;
		}
		else
		{
			if ( count2 != 0 )
			{
				wcscat( stream2, L" " );
			}

			wcscat( stream2, token );
			count2++;
		}
	}

	SetDirty( true );

	PushUndo();

	CCloseCaptionPhrase *newPhrase = new CCloseCaptionPhrase( stream2 );
	phrase->SetStream( stream1 );
	float oldend = phrase->GetEndTime();
	float dt = oldend - phrase->GetStartTime();
	float splitTime = dt * (float)(splitToken+1) / (float)(count);

	phrase->SetEndTime( phrase->GetStartTime() + splitTime );
	newPhrase->SetStartTime( phrase->GetEndTime() );
	newPhrase->SetEndTime( oldend );
	newPhrase->SetSelected( true );

	int first = m_Tags.FindCloseCaptionPhraseIndex( CC_ENGLISH, phrase );
	m_Tags.InsertCloseCaptionPhraseAtIndex( CC_ENGLISH, newPhrase, first + 1 );

	PushRedo();

	redraw();
}

void PhonemeEditor::CloseCaption_SplitPhrase( void )
{
	CCloseCaptionPhrase *phrase = CloseCaption_GetClickedPhrase();
	if ( !phrase )
		return;

	int token = CloseCaption_GetClickedPhraseToken();
	if ( token < 0 )
		return;

	CloseCaption_SplitPhraseAfterToken( phrase, token );

	redraw();
}

void PhonemeEditor::CloseCaption_MergeSelected( void )
{
	CountSelected();
	if ( m_nSelectedPhraseCount < 2 )
	{
		Con_Printf( "CloseCaption_MergeSelected:  requires 2 or more selected phrases\n" );
		return;
	}

	if ( !CloseCaption_AreSelectedPhrasesContiguous() )
	{
		Con_Printf( "CloseCaption_MergeSelected:  selected phrases must be contiguous\n" );
		return;
	}

	SetDirty( true );

	PushUndo();

	CUtlVector< CCloseCaptionPhrase * > selected;

	float beststart = 100000.0f;
	float bestend = -100000.0f;

	int c = m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH );
	int i;
	int insertslot = c -1;

	// Walk backwards and remove
	for ( i = c - 1; i >= 0; i-- )
	{
		CCloseCaptionPhrase *phrase = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i );
		if ( !phrase || !phrase->GetSelected() )
			continue;

		if ( phrase->GetStartTime() < beststart )
		{
			beststart = phrase->GetStartTime();
		}
		if ( phrase->GetEndTime() > bestend )
		{
			bestend = phrase->GetEndTime();
		}

		selected.AddToHead( new CCloseCaptionPhrase( *phrase ) );

		// Remember the earliest slot
		if ( i < insertslot )
		{
			insertslot = i;
		}

		m_Tags.RemoveCloseCaptionPhrase( CC_ENGLISH, i );
	}

	if ( selected.Count() <= 0 )
		return;

	CCloseCaptionPhrase *newphrase = new CCloseCaptionPhrase( selected[ 0 ]->GetStream() );
	Assert( newphrase );
	wchar_t sz[ 4096 ];
	delete selected[ 0 ];
	for ( i = 1; i < selected.Count(); i++ )
	{
		_snwprintf( sz, sizeof( sz ), newphrase->GetStream() );
		// Phrases don't have leading/trailing spaces so it should be safe to just append a space here
		wcscat( sz, L" " );
		wcscat( sz, selected[ i ]->GetStream() );
		newphrase->SetStream( sz );
		delete selected[ i ];
	}
	selected.RemoveAll();

	m_Tags.InsertCloseCaptionPhraseAtIndex( CC_ENGLISH, newphrase, insertslot );
	newphrase->SetSelected( true );
	newphrase->SetStartTime( beststart );
	newphrase->SetEndTime( bestend );

	PushRedo();

	redraw();
}

int PhonemeEditor::CloseCaption_GetPhraseTokenUnderMouse( const CCloseCaptionPhrase *phrase, int mx )
{
	int index = -1;
	int count = phrase->CountTokens();
	if ( count >= 1 )
	{
		RECT rcPhrase;
		CloseCaption_GetPhraseRect( phrase, rcPhrase );

		float t = GetTimeForPixel( mx );
		float dt = phrase->GetEndTime() - phrase->GetStartTime();
		if ( dt > 0.0f )
		{
			float frac = ( t - phrase->GetStartTime() ) / dt;
			if ( frac >= 0 && frac <= 1.0f )
			{
				int availw = rcPhrase.right - rcPhrase.left;

				int clickpoint = frac * availw;

				int pixelsPerToken = availw / count;

				index = clickpoint / pixelsPerToken;
				index = clamp( index, 0, count - 1 );
			}
		}
	}
	return index;
}

void PhonemeEditor::CloseCaption_SortPhrases( bool prepareundo )
{
	if ( prepareundo )
	{
		SetDirty( true );
		PushUndo();
	}

	// Just bubble sort by start time
	int c = m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH );
	for ( int i = 0; i < c; i++ )
	{
		for ( int j = i + 1; j < c; j++ )
		{
			CCloseCaptionPhrase *p1 = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i );
			CCloseCaptionPhrase *p2 = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, j );

			if ( p1->GetStartTime() < p2->GetStartTime() )
				continue;

			// Swap them
			m_Tags.m_CloseCaption[ CC_ENGLISH ][ i ] = p2;
			m_Tags.m_CloseCaption[ CC_ENGLISH ][ j ] = p1;
		}
	}

	if ( prepareundo )
	{
		PushRedo();
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -