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

	CountSelected();

	if ( m_nSelectedPhraseCount < 1 )
		return;

	SetDirty( true );

	PushUndo();

	for ( int i = m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH )- 1; i >= 0; i-- )
	{
		CCloseCaptionPhrase *phrase = m_Tags.GetCloseCaptionPhrase( CC_ENGLISH, i );
		if ( !phrase || !phrase->GetSelected() )
			continue;

		m_Tags.RemoveCloseCaptionPhrase( CC_ENGLISH, i );
	}

	PushRedo();

	redraw();
}
void PhonemeEditor::CloseCaption_ExtendSelectedPhraseEndTime( int direction )
{
	if ( GetMode() != MODE_CLOSECAPTION )
		return;

	CountSelected();

	if ( m_nSelectedPhraseCount != 1 )
		return;

	RECT rc;
	GetWorkspaceRect( rc );

	// Determine start/stop positions
	int totalsamples = (int)( m_pWaveFile->GetRunningLength() * m_pWaveFile->SampleRate() );

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

	float timeperpixel = ( endtime - starttime ) / (float)( rc.right - rc.left );

	float movetime = timeperpixel * (float)direction;

	SetDirty( true );

	PushUndo();

	TraversePhrases( ITER_ExtendSelectedPhraseEndTimes, movetime );

	PushRedo();

	redraw();

	Con_Printf( "Extend phrase end %s\n", direction == -1 ? "left" : "right" );
}
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();
	}
}
示例#4
0
bool CUndoRedo::AddUndo(CTile *Tile)
{
	UndoRecord UndoRec;

	memset(&UndoRec,0,sizeof(UndoRecord));
	UndoRec.TilePointer = Tile;
	UndoRec.Tile = new CTile;
	*UndoRec.Tile = *Tile;
	PushUndo(&UndoRec);

	return true;
}
// Close captioning
void PhonemeEditor::CloseCaption_EditInsertFirstPhrase( void )
{
	if ( GetMode() != MODE_CLOSECAPTION )
		return;

	if ( m_Tags.GetCloseCaptionPhraseCount( CC_ENGLISH ) != 0 )
	{
		Con_Printf( "Can't insert first phrase into sentence, already has data\n" );
		return;
	}

	CEditPhraseParams params;
	memset( &params, 0, sizeof( params ) );
	strcpy( params.m_szDialogTitle, "Edit Phrase" );
	strcpy( params.m_szPrompt, "Current Phrase:" );
	ConvertANSIToUnicode( m_Tags.GetText(), params.m_szInputText, sizeof( params.m_szInputText ) );

	params.m_nLeft = -1;
	params.m_nTop = -1;

	params.m_bPositionDialog = false;

	if ( !EditPhrase( &params ) )
	{
		SetFocus( (HWND)getHandle() );
		return;
	}

	if ( wcslen( params.m_szInputText ) <= 0 )
	{
		return;
	}

	float start, end;
	m_Tags.GetEstimatedTimes( start, end );

	SetDirty( true );

	PushUndo();

	CCloseCaptionPhrase *phrase = new CCloseCaptionPhrase( params.m_szInputText );
	phrase->SetSelected( true );
	phrase->SetStartTime( start );
	phrase->SetEndTime( end );

	m_Tags.AddCloseCaptionPhrase( CC_ENGLISH, phrase );

	PushRedo();

	// Add it
	redraw();
}
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();
	}
}
void PhonemeEditor::CloseCaption_EditPhrase( CCloseCaptionPhrase *phrase )
{
	CEditPhraseParams params;
	memset( &params, 0, sizeof( params ) );
	strcpy( params.m_szDialogTitle, "Edit Phrase" );
	strcpy( params.m_szPrompt, "Current Phrase:" );
	wcscpy( params.m_szInputText, phrase->GetStream() );

	params.m_nLeft = -1;
	params.m_nTop = -1;

	params.m_bPositionDialog = true;

	if ( params.m_bPositionDialog )
	{
		RECT rcPhrase;
		CloseCaption_GetPhraseRect( phrase, rcPhrase );

		// Convert to screen coords
		POINT pt;
		pt.x = rcPhrase.left;
		pt.y = rcPhrase.top;

		ClientToScreen( (HWND)getHandle(), &pt );

		params.m_nLeft	= pt.x;
		params.m_nTop	= pt.y;
	}

	if ( !EditPhrase( &params ) )
	{
		SetFocus( (HWND)getHandle() );
		return;
	}

	SetFocus( (HWND)getHandle() );

	SetDirty( true );

	PushUndo();

	phrase->SetStream( params.m_szInputText );

	PushRedo();

	redraw();
}
void PhonemeEditor::CloseCaption_FinishDrag( 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_FinishMove( 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_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_ShiftSelectedPhrase( int direction )
{
	if ( GetMode() != MODE_CLOSECAPTION )
		return;

	CountSelected();

	switch ( m_nSelectedPhraseCount )
	{
	case 1:
		break;
	case 0:
		Con_Printf( "Can't shift phrases, none selected\n" );
		return;
	default:
		Con_Printf( "Can only shift one phrase at a time via keyboard\n" );
		return;
	}

	RECT rc;
	GetWorkspaceRect( rc );

	// Determine start/stop positions
	int totalsamples = (int)( m_pWaveFile->GetRunningLength() * m_pWaveFile->SampleRate() );

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

	float timeperpixel = ( endtime - starttime ) / (float)( rc.right - rc.left );

	float movetime = timeperpixel * (float)direction;

	float maxmove = CloseCaption_ComputeMaxPhraseShift( direction > 0 ? true : false, false );

	if ( direction > 0 )
	{
		if ( movetime > maxmove )
		{
			movetime = maxmove;
			Con_Printf( "Further shift is blocked on right\n" );
		}
	}
	else
	{
		if ( movetime < -maxmove )
		{
			movetime = -maxmove;
			Con_Printf( "Further shift is blocked on left\n" );
		}
	}

	if ( fabs( movetime ) < 0.0001f )
		return;

	SetDirty( true );

	PushUndo();

	TraversePhrases( ITER_MoveSelectedPhrases, movetime );

	PushRedo();

	redraw();

	Con_Printf( "Shift phrase %s\n", direction == -1 ? "left" : "right" );
}
void PhonemeEditor::CloseCaption_EditInsertAfter( void )
{
	if ( GetMode() != MODE_CLOSECAPTION )
		return;

	CCloseCaptionPhrase *phrase = CloseCaption_GetSelectedPhrase();
	if ( !phrase )
		return;

	float gap = CloseCaption_GetTimeGapToNextPhrase( true, phrase );
	if ( gap < MINIMUM_PHRASE_GAP )
	{
		Con_Printf( "Can't insert after, gap of %.2f ms is too small\n", 1000.0f * gap );
		return;
	}

	// Don't have really long phrases
	gap = min( gap, DEFAULT_PHRASE_LENGTH );

	int clicked = CloseCaption_IndexOfPhrase( phrase );
	Assert( clicked >= 0 );

	CEditPhraseParams params;
	memset( &params, 0, sizeof( params ) );
	strcpy( params.m_szDialogTitle, "Insert Phrase" );
	strcpy( params.m_szPrompt, "Phrase:" );
	wcscpy( params.m_szInputText, L"" );

	params.m_nLeft = -1;
	params.m_nTop = -1;

	params.m_bPositionDialog = true;
	if ( params.m_bPositionDialog )
	{
		RECT rcPhrase;
		CloseCaption_GetPhraseRect( phrase, rcPhrase );

		// Convert to screen coords
		POINT pt;
		pt.x = rcPhrase.left;
		pt.y = rcPhrase.top;

		ClientToScreen( (HWND)getHandle(), &pt );

		params.m_nLeft	= pt.x;
		params.m_nTop	= pt.y;
	}

	int iret = EditPhrase( &params );
	SetFocus( (HWND)getHandle() );
	if ( !iret )
	{
		return;
	}

	if ( wcslen( params.m_szInputText ) <= 0 )
	{
		return;
	}

	SetDirty( true );

	PushUndo();

	CCloseCaptionPhrase *newphrase = new CCloseCaptionPhrase( params.m_szInputText );
	newphrase->SetEndTime( phrase->GetEndTime() + gap );
	newphrase->SetStartTime( phrase->GetEndTime() );
	newphrase->SetSelected( true );
	phrase->SetSelected( false );

	m_Tags.m_CloseCaption[ CC_ENGLISH ].InsertAfter( clicked, newphrase );

	PushRedo();

	// Add it
	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();
}
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();
}