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(); } }
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( ¶ms, 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( ¶ms ) ) { 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( ¶ms, 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( ¶ms ) ) { 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, ¤t, &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( ¶ms, 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( ¶ms ); 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(); }