2006-02-18 22:55:58 +01:00
// Copyright (c) 2006, Rodrigo Braz Monteiro
2006-01-16 22:02:54 +01:00
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB
//
// Website: http://aegisub.cellosoft.com
// Contact: mailto:zeratul@cellosoft.com
//
////////////
// Includes
2006-03-01 04:17:31 +01:00
# include <algorithm>
# include <wx/clipbrd.h>
# include <wx/tokenzr.h>
# include <wx/filename.h>
2006-01-16 22:02:54 +01:00
# include "subs_grid.h"
# include "ass_file.h"
# include "ass_dialogue.h"
# include "ass_style.h"
# include "video_display.h"
# include "vfr.h"
# include "subs_edit_box.h"
# include "options.h"
# include "frame_main.h"
# include "hotkeys.h"
2006-03-01 04:17:31 +01:00
# include "utils.h"
2006-03-11 17:11:55 +01:00
# include "ass_override.h"
2006-12-17 20:41:52 +01:00
# include "dialog_paste_over.h"
2006-01-16 22:02:54 +01:00
///////////////
// Event table
2006-02-18 22:55:58 +01:00
BEGIN_EVENT_TABLE ( SubtitlesGrid , BaseGrid )
2006-01-16 22:02:54 +01:00
EVT_KEY_DOWN ( SubtitlesGrid : : OnKeyDown )
EVT_MENU ( MENU_SWAP , SubtitlesGrid : : OnSwap )
EVT_MENU ( MENU_DUPLICATE , SubtitlesGrid : : OnDuplicate )
EVT_MENU ( MENU_DUPLICATE_NEXT_FRAME , SubtitlesGrid : : OnDuplicateNextFrame )
EVT_MENU ( MENU_JOIN_CONCAT , SubtitlesGrid : : OnJoinConcat )
EVT_MENU ( MENU_JOIN_REPLACE , SubtitlesGrid : : OnJoinReplace )
EVT_MENU ( MENU_ADJOIN , SubtitlesGrid : : OnAdjoin )
EVT_MENU ( MENU_ADJOIN2 , SubtitlesGrid : : OnAdjoin2 )
EVT_MENU ( MENU_INSERT_BEFORE , SubtitlesGrid : : OnInsertBefore )
EVT_MENU ( MENU_INSERT_AFTER , SubtitlesGrid : : OnInsertAfter )
EVT_MENU ( MENU_INSERT_BEFORE_VIDEO , SubtitlesGrid : : OnInsertBeforeVideo )
EVT_MENU ( MENU_INSERT_AFTER_VIDEO , SubtitlesGrid : : OnInsertAfterVideo )
EVT_MENU ( MENU_COPY , SubtitlesGrid : : OnCopyLines )
EVT_MENU ( MENU_PASTE , SubtitlesGrid : : OnPasteLines )
EVT_MENU ( MENU_CUT , SubtitlesGrid : : OnCutLines )
EVT_MENU ( MENU_DELETE , SubtitlesGrid : : OnDeleteLines )
EVT_MENU ( MENU_SET_START_TO_VIDEO , SubtitlesGrid : : OnSetStartToVideo )
EVT_MENU ( MENU_SET_END_TO_VIDEO , SubtitlesGrid : : OnSetEndToVideo )
EVT_MENU ( MENU_SET_VIDEO_TO_START , SubtitlesGrid : : OnSetVideoToStart )
EVT_MENU ( MENU_SET_VIDEO_TO_END , SubtitlesGrid : : OnSetVideoToEnd )
EVT_MENU ( MENU_JOIN_AS_KARAOKE , SubtitlesGrid : : OnJoinAsKaraoke )
2006-03-11 17:11:55 +01:00
EVT_MENU ( MENU_SPLIT_BY_KARAOKE , SubtitlesGrid : : OnSplitByKaraoke )
2006-12-30 23:38:05 +01:00
EVT_MENU ( MENU_RECOMBINE , SubtitlesGrid : : OnRecombine )
2007-01-17 06:06:17 +01:00
EVT_MENU ( MENU_AUDIOCLIP , SubtitlesGrid : : OnAudioClip )
2006-06-27 07:13:41 +02:00
EVT_MENU_RANGE ( MENU_SHOW_COL , MENU_SHOW_COL + 15 , SubtitlesGrid : : OnShowColMenu )
2006-01-16 22:02:54 +01:00
END_EVENT_TABLE ( )
///////////////
// Constructor
2007-01-21 18:01:22 +01:00
SubtitlesGrid : : SubtitlesGrid ( FrameMain * parentFr , wxWindow * parent , wxWindowID id , const wxPoint & pos , const wxSize & size , long style , const wxString & name )
2006-02-18 22:55:58 +01:00
: BaseGrid ( parent , id , pos , size , style , name )
2006-01-16 22:02:54 +01:00
{
// Vars
byFrame = false ;
ass = NULL ;
editBox = NULL ;
parentFrame = parentFr ;
}
//////////////
// Destructor
SubtitlesGrid : : ~ SubtitlesGrid ( ) {
}
//////////////
// Popup menu
2006-06-27 07:13:41 +02:00
void SubtitlesGrid : : OnPopupMenu ( bool alternate ) {
// Alternate
if ( alternate ) {
// Prepare strings
wxArrayString strings ;
strings . Add ( _ ( " Line Number " ) ) ;
strings . Add ( _ ( " Layer " ) ) ;
strings . Add ( _ ( " Start " ) ) ;
strings . Add ( _ ( " End " ) ) ;
strings . Add ( _ ( " Style " ) ) ;
strings . Add ( _ ( " Actor " ) ) ;
strings . Add ( _ ( " Effect " ) ) ;
strings . Add ( _ ( " Left " ) ) ;
strings . Add ( _ ( " Right " ) ) ;
strings . Add ( _ ( " Vert " ) ) ;
// Create Menu
wxMenu menu ;
for ( size_t i = 0 ; i < strings . Count ( ) ; i + + ) {
menu . Append ( MENU_SHOW_COL + i , strings [ i ] , _T ( " " ) , wxITEM_CHECK ) - > Check ( showCol [ i ] ) ;
}
PopupMenu ( & menu ) ;
return ;
}
2006-01-16 22:02:54 +01:00
// Get selections
bool continuous ;
wxArrayInt selections = GetSelection ( & continuous ) ;
int sels = selections . Count ( ) ;
// Show menu if at least one is selected
if ( sels > 0 ) {
wxMenu menu ;
bool state ;
// Insert
state = ( sels = = 1 ) ;
menu . Append ( MENU_INSERT_BEFORE , _ ( " &Insert (before) " ) , _T ( " Inserts a line before current " ) ) - > Enable ( state ) ;
menu . Append ( MENU_INSERT_AFTER , _ ( " Insert (after) " ) , _T ( " Inserts a line after current " ) ) - > Enable ( state ) ;
2007-01-21 18:01:22 +01:00
state = ( sels = = 1 & & VideoContext : : Get ( ) - > IsLoaded ( ) ) ;
2006-01-16 22:02:54 +01:00
menu . Append ( MENU_INSERT_BEFORE_VIDEO , _ ( " Insert at video time (before) " ) , _T ( " Inserts a line after current, starting at video time " ) ) - > Enable ( state ) ;
menu . Append ( MENU_INSERT_AFTER_VIDEO , _ ( " Insert at video time (after) " ) , _T ( " Inserts a line after current, starting at video time " ) ) - > Enable ( state ) ;
menu . AppendSeparator ( ) ;
// Video/time sync
2007-01-21 07:30:19 +01:00
//state = (video && VideoContext::Get()->IsLoaded());
2006-03-06 00:01:02 +01:00
//menu.Append(MENU_SET_VIDEO_TO_START,_("Jump video to start"),_T("Sets current video time to start time"))->Enable(state);
//menu.Append(MENU_SET_VIDEO_TO_END,_("Jump video to end"),_T("Sets current video time to end time"))->Enable(state);
//menu.Append(MENU_SET_START_TO_VIDEO,_("Set start to video"),_T("Sets start times to current video time"))->Enable(state);
//menu.Append(MENU_SET_END_TO_VIDEO,_("Set end to video"),_T("Sets end times to current video time"))->Enable(state);
//menu.AppendSeparator();
2006-01-16 22:02:54 +01:00
// Duplicate selection
2007-07-05 17:51:42 +02:00
menu . Append ( MENU_DUPLICATE , _ ( " &Duplicate " ) , _ ( " Duplicate the selected lines " ) ) - > Enable ( continuous ) ;
menu . Append ( MENU_DUPLICATE_NEXT_FRAME , _ ( " &Duplicate and shift by 1 frame " ) , _ ( " Duplicate lines and shift by one frame " ) ) - > Enable ( continuous & & VFR_Output . IsLoaded ( ) ) ;
menu . Append ( MENU_SPLIT_BY_KARAOKE , _ ( " Split (by karaoke) " ) , _ ( " Uses karaoke timing to split line into multiple smaller lines " ) ) - > Enable ( sels > 0 ) ;
2006-01-16 22:02:54 +01:00
// Swaps selection
state = ( sels = = 2 ) ;
2007-07-05 17:51:42 +02:00
menu . Append ( MENU_SWAP , _ ( " &Swap " ) , _ ( " Swaps the two selected lines " ) ) - > Enable ( state ) ;
2006-01-16 22:02:54 +01:00
// Join selection
state = ( sels > = 2 & & continuous ) ;
2007-07-05 17:51:42 +02:00
menu . Append ( MENU_JOIN_CONCAT , _ ( " &Join (concatenate) " ) , _ ( " Joins selected lines in a single one, concatenating text together " ) ) - > Enable ( state ) ;
menu . Append ( MENU_JOIN_REPLACE , _ ( " Join (keep first) " ) , _ ( " Joins selected lines in a single one, keeping text of first and discarding remaining " ) ) - > Enable ( state ) ;
menu . Append ( MENU_JOIN_AS_KARAOKE , _ ( " Join (as Karaoke) " ) , _ ( " Joins selected lines in a single one, making each line into a karaoke syllable " ) ) - > Enable ( state ) ;
2006-12-30 23:38:05 +01:00
menu . AppendSeparator ( ) ;
2006-01-16 22:02:54 +01:00
// Adjoin selection
2007-07-05 17:51:42 +02:00
menu . Append ( MENU_ADJOIN , _ ( " &Make times continuous (change start) " ) , _ ( " Changes times of subs so start times begin on previous's end time " ) ) - > Enable ( state ) ;
menu . Append ( MENU_ADJOIN2 , _ ( " &Make times continuous (change end) " ) , _ ( " Changes times of subs so end times begin on next's start time " ) ) - > Enable ( state ) ;
2006-01-16 22:02:54 +01:00
// Recombine selection
2006-12-30 23:38:05 +01:00
state = ( sels = = 2 | | sels = = 3 ) & & continuous ;
2007-07-05 17:51:42 +02:00
menu . Append ( MENU_RECOMBINE , _ ( " Recombine Lines " ) , _ ( " Recombine subtitles when they have been split and merged " ) ) - > Enable ( state ) ;
2006-01-16 22:02:54 +01:00
menu . AppendSeparator ( ) ;
2007-01-17 06:06:17 +01:00
//Make audio clip
2007-03-19 21:01:09 +01:00
state = parentFrame - > audioBox - > audioDisplay - > loaded = = true ;
2007-07-05 17:51:42 +02:00
menu . Append ( MENU_AUDIOCLIP , _ ( " Create audio clip " ) , _ ( " Create an audio clip of the selected line " ) ) - > Enable ( state ) ;
2007-01-17 06:06:17 +01:00
menu . AppendSeparator ( ) ;
2006-01-16 22:02:54 +01:00
// Copy/cut/paste
2007-07-05 17:51:42 +02:00
menu . Append ( MENU_COPY , _ ( " &Copy " ) , _ ( " Copies selected lines to clipboard " ) ) ;
menu . Append ( MENU_CUT , _ ( " C&ut " ) , _ ( " Cuts selected lines to clipboard " ) ) ;
menu . Append ( MENU_PASTE , _ ( " &Paste " ) , _ ( " Paste lines from clipboard " ) ) ;
2006-01-16 22:02:54 +01:00
menu . AppendSeparator ( ) ;
// Delete
2007-07-05 17:51:42 +02:00
menu . Append ( MENU_DELETE , _ ( " Delete " ) , _ ( " Delete currently selected lines " ) ) ;
2006-01-16 22:02:54 +01:00
PopupMenu ( & menu ) ;
}
}
2006-06-27 07:13:41 +02:00
////////////////////////////////////
// Process a show/hide column event
void SubtitlesGrid : : OnShowColMenu ( wxCommandEvent & event ) {
// Set width
int item = event . GetId ( ) - MENU_SHOW_COL ;
showCol [ item ] = ! showCol [ item ] ;
// Save options
Options . SetBool ( _T ( " Grid show column " ) + IntegerToString ( item ) , showCol [ item ] ) ;
Options . Save ( ) ;
// Update
SetColumnWidths ( ) ;
Refresh ( false ) ;
}
2006-01-16 22:02:54 +01:00
///////////////////////////
// Process keyboard events
void SubtitlesGrid : : OnKeyDown ( wxKeyEvent & event ) {
// Get key
2007-09-22 17:16:48 +02:00
# ifdef __APPLE__
Hotkeys . SetPressed ( event . GetKeyCode ( ) , event . m_metaDown , event . m_altDown , event . m_shiftDown ) ;
# else
2006-01-16 22:02:54 +01:00
Hotkeys . SetPressed ( event . GetKeyCode ( ) , event . m_controlDown , event . m_altDown , event . m_shiftDown ) ;
2007-09-22 17:16:48 +02:00
# endif
2006-01-16 22:02:54 +01:00
// Get selection
bool continuous = false ;
wxArrayInt sels = GetSelection ( & continuous ) ;
int n_found = sels . Count ( ) ;
int n = 0 ;
int n2 = 0 ;
int nrows = GetRows ( ) ;
if ( n_found > 0 ) {
n = sels [ 0 ] ;
n2 = sels [ n_found - 1 ] ;
}
if ( n_found = = 1 ) {
// Move down
if ( Hotkeys . IsPressed ( _T ( " Grid move row down " ) ) ) {
if ( n < nrows - 1 ) {
SwapLines ( n , n + 1 ) ;
SelectRow ( n + 1 ) ;
editBox - > SetToLine ( n + 1 ) ;
}
return ;
}
// Move up
if ( Hotkeys . IsPressed ( _T ( " Grid move row up " ) ) ) {
if ( n > 0 ) {
SwapLines ( n - 1 , n ) ;
SelectRow ( n - 1 ) ;
editBox - > SetToLine ( n - 1 ) ;
}
return ;
}
}
if ( n_found > = 1 ) {
// Copy
if ( Hotkeys . IsPressed ( _T ( " Copy " ) ) ) {
2006-02-23 20:26:14 +01:00
CopyLines ( GetSelection ( ) ) ;
2006-12-24 05:54:35 +01:00
return ;
2006-01-16 22:02:54 +01:00
}
// Cut
if ( Hotkeys . IsPressed ( _T ( " Cut " ) ) ) {
2006-02-23 20:26:14 +01:00
CutLines ( GetSelection ( ) ) ;
2006-12-24 05:54:35 +01:00
return ;
2006-01-16 22:02:54 +01:00
}
// Paste
if ( Hotkeys . IsPressed ( _T ( " Paste " ) ) ) {
2006-02-23 20:26:14 +01:00
PasteLines ( GetFirstSelRow ( ) ) ;
2006-12-24 05:54:35 +01:00
return ;
2006-01-16 22:02:54 +01:00
}
// Delete
if ( Hotkeys . IsPressed ( _T ( " Grid delete rows " ) ) ) {
2006-02-22 07:08:35 +01:00
DeleteLines ( GetSelection ( ) ) ;
2006-01-16 22:02:54 +01:00
return ;
}
if ( continuous ) {
// Duplicate
if ( Hotkeys . IsPressed ( _T ( " Grid duplicate rows " ) ) ) {
DuplicateLines ( n , n2 , false ) ;
return ;
}
// Duplicate and shift
2006-06-27 21:11:41 +02:00
if ( VFR_Output . IsLoaded ( ) ) {
2006-01-16 22:02:54 +01:00
if ( Hotkeys . IsPressed ( _T ( " Grid duplicate and shift one frame " ) ) ) {
DuplicateLines ( n , n2 , true ) ;
return ;
}
}
}
}
event . Skip ( ) ;
}
///////////////////////
// Duplicate selection
void SubtitlesGrid : : OnDuplicate ( wxCommandEvent & WXUNUSED ( & event ) ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-02-22 07:49:20 +01:00
wxArrayInt sels = GetSelection ( ) ;
DuplicateLines ( sels . front ( ) , sels . back ( ) ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
//////////////////////////////////////////////
// Duplicate selection and shift by one frame
void SubtitlesGrid : : OnDuplicateNextFrame ( wxCommandEvent & WXUNUSED ( & event ) ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-02-22 07:49:20 +01:00
wxArrayInt sels = GetSelection ( ) ;
DuplicateLines ( sels . front ( ) , sels . back ( ) , true ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
/////////////
// Call swap
void SubtitlesGrid : : OnSwap ( wxCommandEvent & event ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-02-22 07:49:20 +01:00
wxArrayInt sels = GetSelection ( ) ;
SwapLines ( sels . front ( ) , sels . back ( ) ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
///////////////////////////
// Call join (concatenate)
void SubtitlesGrid : : OnJoinConcat ( wxCommandEvent & event ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-02-22 07:49:20 +01:00
wxArrayInt sels = GetSelection ( ) ;
JoinLines ( sels . front ( ) , sels . back ( ) , true ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
///////////////////////
// Call join (replace)
void SubtitlesGrid : : OnJoinReplace ( wxCommandEvent & event ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-02-22 07:49:20 +01:00
wxArrayInt sels = GetSelection ( ) ;
JoinLines ( sels . front ( ) , sels . back ( ) , false ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
////////////////
// Adjoin lines
void SubtitlesGrid : : OnAdjoin ( wxCommandEvent & event ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-02-22 07:49:20 +01:00
wxArrayInt sels = GetSelection ( ) ;
AdjoinLines ( sels . front ( ) , sels . back ( ) , true ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
void SubtitlesGrid : : OnAdjoin2 ( wxCommandEvent & event ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-02-22 07:49:20 +01:00
wxArrayInt sels = GetSelection ( ) ;
AdjoinLines ( sels . front ( ) , sels . back ( ) , false ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
////////////////////////
// Call join as karaoke
void SubtitlesGrid : : OnJoinAsKaraoke ( wxCommandEvent & event ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-02-22 07:49:20 +01:00
wxArrayInt sels = GetSelection ( ) ;
JoinAsKaraoke ( sels . front ( ) , sels . back ( ) ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
2006-03-11 17:11:55 +01:00
/////////////////////////
// Call split by karaoke
void SubtitlesGrid : : OnSplitByKaraoke ( wxCommandEvent & event ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-03-11 17:11:55 +01:00
wxArrayInt sels = GetSelection ( ) ;
for ( int i = sels . size ( ) - 1 ; i > = 0 ; i - - ) {
SplitLineByKaraoke ( sels [ i ] ) ;
}
2007-01-26 01:47:42 +01:00
ass - > FlagAsModified ( _ ( " splitting " ) ) ;
2006-03-11 17:11:55 +01:00
CommitChanges ( ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-03-11 17:11:55 +01:00
}
2006-01-16 22:02:54 +01:00
//////////////////////
// Call insert before
void SubtitlesGrid : : OnInsertBefore ( wxCommandEvent & event ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-01-16 22:02:54 +01:00
// Find line
2006-02-22 07:49:20 +01:00
int n = GetFirstSelRow ( ) ;
2006-01-16 22:02:54 +01:00
// Create line to add
AssDialogue * def = new AssDialogue ;
if ( n = = 0 ) {
def - > Start . SetMS ( 0 ) ;
def - > End = GetDialogue ( n ) - > Start ;
}
else {
def - > Start = GetDialogue ( n - 1 ) - > End ;
def - > End = GetDialogue ( n ) - > Start ;
}
2007-07-03 08:43:57 +02:00
if ( def - > End . GetMS ( ) < def - > Start . GetMS ( ) ) def - > End . SetMS ( def - > Start . GetMS ( ) + Options . AsInt ( _T ( " Timing Default Duration " ) ) ) ;
2006-01-16 22:02:54 +01:00
def - > Style = GetDialogue ( n ) - > Style ;
// Insert it
InsertLine ( def , n , false ) ;
2006-02-21 22:23:52 +01:00
SelectRow ( n ) ;
editBox - > SetToLine ( n ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
/////////////////////
// Call insert after
void SubtitlesGrid : : OnInsertAfter ( wxCommandEvent & event ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-01-16 22:02:54 +01:00
// Find line
2006-02-22 07:49:20 +01:00
int n = GetFirstSelRow ( ) ;
2006-01-16 22:02:54 +01:00
int nrows = GetRows ( ) ;
// Create line to add
AssDialogue * def = new AssDialogue ;
if ( n = = nrows - 1 ) {
def - > Start = GetDialogue ( n ) - > End ;
def - > End = GetDialogue ( n ) - > End ;
2007-07-03 08:43:57 +02:00
def - > End . SetMS ( def - > End . GetMS ( ) + Options . AsInt ( _T ( " Timing Default Duration " ) ) ) ;
2006-01-16 22:02:54 +01:00
}
else {
def - > Start = GetDialogue ( n ) - > End ;
def - > End = GetDialogue ( n + 1 ) - > Start ;
}
2007-07-03 08:43:57 +02:00
if ( def - > End . GetMS ( ) < def - > Start . GetMS ( ) ) def - > End . SetMS ( def - > Start . GetMS ( ) + Options . AsInt ( _T ( " Timing Default Duration " ) ) ) ;
2006-01-16 22:02:54 +01:00
def - > Style = GetDialogue ( n ) - > Style ;
// Insert it
InsertLine ( def , n , true ) ;
2006-02-21 22:23:52 +01:00
SelectRow ( n + 1 ) ;
editBox - > SetToLine ( n + 1 ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
/////////////////////////////////
// Call insert before with video
void SubtitlesGrid : : OnInsertBeforeVideo ( wxCommandEvent & event ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-01-16 22:02:54 +01:00
// Find line
2006-02-22 07:49:20 +01:00
int n = GetFirstSelRow ( ) ;
2006-01-16 22:02:54 +01:00
// Create line to add
AssDialogue * def = new AssDialogue ;
2007-01-21 07:30:19 +01:00
int video_ms = VFR_Output . GetTimeAtFrame ( VideoContext : : Get ( ) - > GetFrameN ( ) , true ) ;
2006-01-16 22:02:54 +01:00
def - > Start . SetMS ( video_ms ) ;
2007-07-03 08:43:57 +02:00
def - > End . SetMS ( video_ms + Options . AsInt ( _T ( " Timing Default Duration " ) ) ) ;
2006-01-16 22:02:54 +01:00
def - > Style = GetDialogue ( n ) - > Style ;
// Insert it
InsertLine ( def , n , false ) ;
2006-02-21 22:23:52 +01:00
SelectRow ( n ) ;
editBox - > SetToLine ( n ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
////////////////////////////////
// Call insert after with video
void SubtitlesGrid : : OnInsertAfterVideo ( wxCommandEvent & event ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-01-16 22:02:54 +01:00
// Find line
2006-02-22 07:49:20 +01:00
int n = GetFirstSelRow ( ) ;
2006-01-16 22:02:54 +01:00
// Create line to add
AssDialogue * def = new AssDialogue ;
2007-01-21 07:30:19 +01:00
int video_ms = VFR_Output . GetTimeAtFrame ( VideoContext : : Get ( ) - > GetFrameN ( ) , true ) ;
2006-01-16 22:02:54 +01:00
def - > Start . SetMS ( video_ms ) ;
2007-07-03 08:43:57 +02:00
def - > End . SetMS ( video_ms + Options . AsInt ( _T ( " Timing Default Duration " ) ) ) ;
2006-01-16 22:02:54 +01:00
def - > Style = GetDialogue ( n ) - > Style ;
// Insert it
InsertLine ( def , n , true ) ;
2006-02-21 22:23:52 +01:00
SelectRow ( n + 1 ) ;
editBox - > SetToLine ( n + 1 ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
///////////////////////////////
// Copy selection to clipboard
void SubtitlesGrid : : OnCopyLines ( wxCommandEvent & WXUNUSED ( & event ) ) {
2006-02-22 07:49:20 +01:00
CopyLines ( GetSelection ( ) ) ;
2006-01-16 22:02:54 +01:00
}
///////////////////////////////
// Cuts selection to clipboard
void SubtitlesGrid : : OnCutLines ( wxCommandEvent & WXUNUSED ( & event ) ) {
2006-02-22 07:49:20 +01:00
CutLines ( GetSelection ( ) ) ;
2006-01-16 22:02:54 +01:00
}
////////////////////////
// Paste from clipboard
void SubtitlesGrid : : OnPasteLines ( wxCommandEvent & WXUNUSED ( & event ) ) {
2006-02-22 05:59:39 +01:00
PasteLines ( GetFirstSelRow ( ) ) ;
2006-01-16 22:02:54 +01:00
}
///////////////////////////////
// Copy selection to clipboard
void SubtitlesGrid : : OnDeleteLines ( wxCommandEvent & WXUNUSED ( & event ) ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-02-22 07:08:35 +01:00
DeleteLines ( GetSelection ( ) ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
//////////////////////////
// Set start to video pos
void SubtitlesGrid : : OnSetStartToVideo ( wxCommandEvent & event ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-02-22 05:59:39 +01:00
SetSubsToVideo ( true ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
////////////////////////
// Set end to video pos
void SubtitlesGrid : : OnSetEndToVideo ( wxCommandEvent & event ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-02-22 05:59:39 +01:00
SetSubsToVideo ( false ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
//////////////////////////
// Set video pos to start
void SubtitlesGrid : : OnSetVideoToStart ( wxCommandEvent & event ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-02-22 05:59:39 +01:00
SetVideoToSubs ( true ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
////////////////////////
// Set video pos to end
void SubtitlesGrid : : OnSetVideoToEnd ( wxCommandEvent & event ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-02-22 05:59:39 +01:00
SetVideoToSubs ( false ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
2006-12-30 23:38:05 +01:00
//////////////
// Recombine
void SubtitlesGrid : : OnRecombine ( wxCommandEvent & event ) {
2006-01-16 22:02:54 +01:00
// Get selection
bool cont ;
wxArrayInt sel = GetSelection ( & cont ) ;
2006-12-30 23:38:05 +01:00
int nSel = sel . Count ( ) ;
2007-07-18 15:46:38 +02:00
if ( ( nSel ! = 2 & & nSel ! = 3 ) | | ! cont ) throw _T ( " Invalid selection for recombining " ) ;
2006-01-16 22:02:54 +01:00
int n = sel [ 0 ] ;
2006-12-30 23:38:05 +01:00
// Get dialogues
2006-01-16 22:02:54 +01:00
AssDialogue * n1 , * n2 , * n3 ;
n1 = GetDialogue ( n ) ;
n2 = GetDialogue ( n + 1 ) ;
2006-12-30 23:38:05 +01:00
// 1,1+2,2 -> 1,2
if ( nSel = = 3 ) {
n3 = GetDialogue ( n + 2 ) ;
n1 - > End = n2 - > End ;
n3 - > Start = n2 - > Start ;
2006-02-01 03:16:57 +01:00
n1 - > UpdateData ( ) ;
2006-12-30 23:38:05 +01:00
n3 - > UpdateData ( ) ;
DeleteLines ( GetRangeArray ( n + 1 , n + 1 ) ) ;
2006-02-01 03:16:57 +01:00
}
2006-11-23 20:08:46 +01:00
2006-12-30 23:38:05 +01:00
// 2 Line recombine
else {
// Trim dialogues
n1 - > Text . Trim ( true ) . Trim ( false ) ;
n2 - > Text . Trim ( true ) . Trim ( false ) ;
// Detect type
int type = - 1 ;
2007-01-26 05:11:32 +01:00
bool invert = false ;
2006-12-30 23:38:05 +01:00
if ( n1 - > Text . Right ( n2 - > Text . Length ( ) ) = = n2 - > Text ) type = 0 ;
2007-01-26 05:11:32 +01:00
else if ( n1 - > Text . Left ( n2 - > Text . Length ( ) ) = = n2 - > Text ) { type = 1 ; invert = true ; }
2006-12-30 23:38:05 +01:00
else if ( n2 - > Text . Left ( n1 - > Text . Length ( ) ) = = n1 - > Text ) type = 1 ;
2007-01-26 05:11:32 +01:00
else if ( n2 - > Text . Right ( n1 - > Text . Length ( ) ) = = n1 - > Text ) { type = 0 ; invert = true ; }
2006-12-30 23:38:05 +01:00
else {
// Unknown type
parentFrame - > StatusTimeout ( _T ( " Unable to recombine: Neither line is a suffix of the other one. " ) ) ;
return ;
}
2006-01-16 22:02:54 +01:00
2007-01-26 05:11:32 +01:00
// Invert?
if ( invert ) {
n3 = n1 ;
n1 = n2 ;
n2 = n3 ;
n3 = NULL ;
}
2006-12-30 23:38:05 +01:00
// 1+2,2 -> 1,2
if ( type = = 0 ) {
n1 - > Text = n1 - > Text . SubString ( 0 , n1 - > Text . Length ( ) - n2 - > Text . Length ( ) - 1 ) . Trim ( true ) . Trim ( false ) ;
while ( n1 - > Text . Left ( 2 ) = = _T ( " \\ N " ) | | n1 - > Text . Left ( 2 ) = = _T ( " \\ n " ) ) n1 - > Text = n1 - > Text . Mid ( 2 ) ;
while ( n1 - > Text . Right ( 2 ) = = _T ( " \\ N " ) | | n1 - > Text . Right ( 2 ) = = _T ( " \\ n " ) ) n1 - > Text = n1 - > Text . Mid ( 0 , n1 - > Text . Length ( ) - 2 ) ;
n2 - > Start = n1 - > Start ;
}
2006-11-23 20:08:46 +01:00
2007-01-26 05:11:32 +01:00
// 1,1+2 -> 1,2
else if ( type = = 1 ) {
2006-12-30 23:38:05 +01:00
n2 - > Text = n2 - > Text . Mid ( n1 - > Text . Length ( ) ) . Trim ( true ) . Trim ( false ) ;
while ( n2 - > Text . Left ( 2 ) = = _T ( " \\ N " ) | | n2 - > Text . Left ( 2 ) = = _T ( " \\ n " ) ) n2 - > Text = n2 - > Text . Mid ( 2 ) ;
while ( n2 - > Text . Right ( 2 ) = = _T ( " \\ N " ) | | n2 - > Text . Right ( 2 ) = = _T ( " \\ n " ) ) n2 - > Text = n2 - > Text . Mid ( 0 , n2 - > Text . Length ( ) - 2 ) ;
n1 - > End = n2 - > End ;
}
2006-01-16 22:02:54 +01:00
2006-12-30 23:38:05 +01:00
// Commit
2006-02-01 03:16:57 +01:00
n1 - > UpdateData ( ) ;
n2 - > UpdateData ( ) ;
2007-01-26 01:47:42 +01:00
ass - > FlagAsModified ( _ ( " combining " ) ) ;
2006-02-01 03:16:57 +01:00
CommitChanges ( ) ;
}
2006-11-23 20:08:46 +01:00
2006-12-30 23:38:05 +01:00
// Adjus scrollbar
AdjustScrollbar ( ) ;
2006-01-16 22:02:54 +01:00
}
2007-01-17 06:06:17 +01:00
//////////////
// Export audio clip of line
void SubtitlesGrid : : OnAudioClip ( wxCommandEvent & event ) {
2007-08-31 16:11:35 +02:00
int64_t num_samples , start = 0 , end = 0 , temp ;
2007-01-17 06:06:17 +01:00
AudioDisplay * audioDisplay = parentFrame - > audioBox - > audioDisplay ;
AudioProvider * provider = audioDisplay - > provider ;
2007-03-19 21:01:09 +01:00
AssDialogue * cur ;
wxArrayInt sel = GetSelection ( ) ;
num_samples = provider - > GetNumSamples ( ) ;
2007-04-04 22:42:44 +02:00
for ( unsigned int i = 0 ; i ! = sel . GetCount ( ) ; i + + ) {
2007-03-19 21:01:09 +01:00
cur = GetDialogue ( sel [ i ] ) ;
temp = audioDisplay - > GetSampleAtMS ( cur - > Start . GetMS ( ) ) ;
start = ( i = = 0 | | temp < start ) ? temp : start ;
temp = audioDisplay - > GetSampleAtMS ( cur - > End . GetMS ( ) ) ;
end = ( i = = 0 | | temp > end ) ? temp : end ;
}
if ( start > num_samples ) {
wxMessageBox ( _ ( " The starting point is beyond the length of the audio loaded. " ) , _ ( " Error " ) ) ;
return ;
}
if ( start = = end | | end = = 0 ) {
wxMessageBox ( _ ( " There is no audio to save. " ) , _ ( " Error " ) ) ;
return ;
}
end = ( end > num_samples ) ? num_samples : end ;
2007-01-17 06:06:17 +01:00
2007-08-07 22:45:41 +02:00
wxString filename = wxFileSelector ( _ ( " Save audio clip " ) , _T ( " " ) , _T ( " " ) , _T ( " wav " ) , _T ( " " ) , wxFD_SAVE | wxFD_OVERWRITE_PROMPT , this ) ;
2007-01-17 06:06:17 +01:00
if ( ! filename . empty ( ) ) {
2007-01-17 07:18:12 +01:00
std : : ofstream outfile ( filename . mb_str ( wxConvLocal ) , std : : ios : : binary ) ;
2007-01-17 06:06:17 +01:00
size_t bufsize = ( end - start ) * provider - > GetChannels ( ) * provider - > GetBytesPerSample ( ) ;
int intval ;
short shortval ;
outfile < < " RIFF " ;
outfile . write ( ( char * ) & ( intval = bufsize + 36 ) , 4 ) ;
outfile < < " WAVEfmt " ;
outfile . write ( ( char * ) & ( intval = 16 ) , 4 ) ;
outfile . write ( ( char * ) & ( shortval = 1 ) , 2 ) ;
outfile . write ( ( char * ) & ( shortval = provider - > GetChannels ( ) ) , 2 ) ;
outfile . write ( ( char * ) & ( intval = provider - > GetSampleRate ( ) ) , 4 ) ;
outfile . write ( ( char * ) & ( intval = provider - > GetSampleRate ( ) * provider - > GetChannels ( ) * provider - > GetBytesPerSample ( ) ) , 4 ) ;
outfile . write ( ( char * ) & ( intval = provider - > GetChannels ( ) * provider - > GetBytesPerSample ( ) ) , 2 ) ;
outfile . write ( ( char * ) & ( shortval = provider - > GetBytesPerSample ( ) < < 3 ) , 2 ) ;
outfile < < " data " ;
outfile . write ( ( char * ) & bufsize , 4 ) ;
//samples per read
size_t spr = 65536 / ( provider - > GetBytesPerSample ( ) * provider - > GetChannels ( ) ) ;
for ( int i = start ; i < end ; i + = spr ) {
int len = ( i + spr > end ) ? ( end - i ) : spr ;
2007-01-17 06:13:02 +01:00
bufsize = len * ( provider - > GetBytesPerSample ( ) * provider - > GetChannels ( ) ) ;
void * buf = malloc ( bufsize ) ;
2007-01-17 06:06:17 +01:00
if ( buf ) {
provider - > GetAudio ( buf , i , len ) ;
2007-01-17 06:13:02 +01:00
outfile . write ( ( char * ) buf , bufsize ) ;
2007-01-17 06:06:17 +01:00
free ( buf ) ;
}
else if ( spr > 128 ) {
//maybe we can allocate a smaller amount of memory
i - = spr ; //effectively redo this loop again
spr = 128 ;
}
else {
wxMessageBox ( _ ( " Couldn't allocate memory. " ) , _ ( " Error " ) , wxICON_ERROR | wxOK ) ;
2007-01-17 07:38:26 +01:00
break ; // don't return, we need to close the file
2007-01-17 06:06:17 +01:00
}
}
outfile . close ( ) ;
}
}
2006-01-16 22:02:54 +01:00
//////////////////////////////////////
// Clears grid and sets it to default
void SubtitlesGrid : : LoadDefault ( AssFile * _ass ) {
if ( _ass ) {
ass = _ass ;
}
ass - > LoadDefault ( ) ;
LoadFromAss ( NULL , false , true ) ;
}
/////////////////////////////////////
// Read data from ASS file structure
void SubtitlesGrid : : LoadFromAss ( AssFile * _ass , bool keepSelection , bool dontModify ) {
// Store selected rows
std : : vector < int > srows ;
if ( keepSelection ) {
int nrows = GetRows ( ) ;
for ( int i = 0 ; i < nrows ; i + + ) {
if ( IsInSelection ( i , 0 ) ) {
srows . push_back ( i ) ;
}
}
}
2006-02-25 04:04:52 +01:00
// Clear grid
2006-01-16 22:02:54 +01:00
BeginBatch ( ) ;
2006-02-25 04:04:52 +01:00
int oldPos = yPos ;
2006-01-16 22:02:54 +01:00
Clear ( ) ;
2006-02-25 04:04:52 +01:00
if ( keepSelection ) yPos = oldPos ;
2007-06-28 22:29:56 +02:00
// Clear from video
VideoContext : : Get ( ) - > curLine = NULL ;
2006-02-25 04:04:52 +01:00
// Get subtitles
2006-01-16 22:02:54 +01:00
if ( _ass ) ass = _ass ;
else {
if ( ! ass ) throw _T ( " Trying to set subs grid to current ass file, but there is none " ) ;
}
// Run through subs adding them
int n = 0 ;
AssDialogue * curdiag ;
ready = false ;
for ( entryIter cur = ass - > Line . begin ( ) ; cur ! = ass - > Line . end ( ) ; cur + + ) {
curdiag = AssEntry : : GetAsDialogue ( * cur ) ;
if ( curdiag ) {
diagMap . push_back ( cur ) ;
2006-02-21 03:01:42 +01:00
diagPtrMap . push_back ( curdiag ) ;
2006-02-18 22:55:58 +01:00
selMap . push_back ( false ) ;
2006-01-16 22:02:54 +01:00
n + + ;
}
}
ready = true ;
// Restore selection
if ( keepSelection ) {
for ( size_t i = 0 ; i < srows . size ( ) ; i + + ) {
SelectRow ( srows . at ( i ) , true ) ;
}
}
// Select first
else {
SelectRow ( 0 ) ;
}
// Commit
if ( ! AssFile : : Popping ) {
2007-01-26 01:47:42 +01:00
if ( dontModify ) AssFile : : StackPush ( _ ( " load " ) ) ;
else ass - > FlagAsModified ( _ ( " load " ) ) ;
2006-01-16 22:02:54 +01:00
}
CommitChanges ( ) ;
// Set edit box
if ( editBox ) {
int nrows = GetRows ( ) ;
int firstsel = - 1 ;
for ( int i = 0 ; i < nrows ; i + + ) {
if ( IsInSelection ( i , 0 ) ) {
firstsel = i ;
break ;
}
}
editBox - > UpdateGlobals ( ) ;
if ( _ass ) editBox - > SetToLine ( firstsel ) ;
}
2006-02-25 04:04:52 +01:00
// Finish setting layout
AdjustScrollbar ( ) ;
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
///////////////////
// Swaps two lines
void SubtitlesGrid : : SwapLines ( int n1 , int n2 ) {
// Check bounds and get iterators
int rows = GetRows ( ) ;
if ( n1 < 0 | | n2 < 0 | | n1 > = rows | | n2 > = rows ) return ;
entryIter src1 = diagMap . at ( n1 ) ;
entryIter src2 = diagMap . at ( n2 ) ;
// Swaps
iter_swap ( src1 , src2 ) ;
// Update mapping
diagMap [ n1 ] = src1 ;
2006-02-22 07:08:35 +01:00
diagPtrMap [ n1 ] = ( AssDialogue * ) * src1 ;
2006-01-16 22:02:54 +01:00
diagMap [ n2 ] = src2 ;
2006-02-22 07:08:35 +01:00
diagPtrMap [ n2 ] = ( AssDialogue * ) * src2 ;
2007-01-26 01:47:42 +01:00
ass - > FlagAsModified ( _ ( " swap lines " ) ) ;
2006-01-16 22:02:54 +01:00
CommitChanges ( ) ;
}
/////////////////
// Insert a line
void SubtitlesGrid : : InsertLine ( AssDialogue * line , int n , bool after , bool update ) {
// Check bounds and get iterators
entryIter pos = diagMap . at ( n ) ;
// Insert
if ( after ) {
n + + ;
pos + + ;
}
line - > UpdateData ( ) ;
entryIter newIter = ass - > Line . insert ( pos , line ) ;
2006-02-18 22:55:58 +01:00
//InsertRows(n);
//SetRowToLine(n,line);
2006-01-16 22:02:54 +01:00
diagMap . insert ( diagMap . begin ( ) + n , newIter ) ;
2006-02-22 07:08:35 +01:00
diagPtrMap . insert ( diagPtrMap . begin ( ) + n , ( AssDialogue * ) ( * newIter ) ) ;
2006-02-18 22:55:58 +01:00
selMap . insert ( selMap . begin ( ) + n , false ) ;
2006-01-16 22:02:54 +01:00
// Update
if ( update ) {
2007-01-26 01:47:42 +01:00
ass - > FlagAsModified ( _ ( " line insertion " ) ) ;
2006-01-16 22:02:54 +01:00
CommitChanges ( ) ;
2007-04-13 17:30:57 +02:00
AdjustScrollbar ( ) ;
2006-01-16 22:02:54 +01:00
}
}
///////////////////////////
// Copy lines to clipboard
2006-02-22 07:49:20 +01:00
void SubtitlesGrid : : CopyLines ( wxArrayInt target ) {
2006-01-16 22:02:54 +01:00
// Prepare text
wxString data = _T ( " " ) ;
AssDialogue * cur ;
2006-02-22 07:49:20 +01:00
int nrows = target . Count ( ) ;
2006-01-16 22:02:54 +01:00
bool first = true ;
for ( int i = 0 ; i < nrows ; i + + ) {
2006-02-22 07:49:20 +01:00
if ( ! first ) data + = _T ( " \r \n " ) ;
first = false ;
cur = GetDialogue ( target [ i ] ) ;
2006-02-27 03:23:50 +01:00
data + = cur - > GetEntryData ( ) ;
2006-01-16 22:02:54 +01:00
}
// Send to clipboard
if ( wxTheClipboard - > Open ( ) ) {
wxTheClipboard - > SetData ( new wxTextDataObject ( data ) ) ;
wxTheClipboard - > Close ( ) ;
}
}
2006-02-22 05:59:39 +01:00
////////////////////
// Cut to clipboard
2006-02-22 07:49:20 +01:00
void SubtitlesGrid : : CutLines ( wxArrayInt target ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-02-22 07:49:20 +01:00
CopyLines ( target ) ;
DeleteLines ( target ) ;
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-02-22 05:59:39 +01:00
}
2006-01-16 22:02:54 +01:00
//////////////////////////////
// Paste lines from clipboard
2006-12-17 19:30:19 +01:00
void SubtitlesGrid : : PasteLines ( int n , bool pasteOver ) {
2006-11-23 20:08:46 +01:00
BeginBatch ( ) ;
2006-01-16 22:02:54 +01:00
// Prepare text
wxString data = _T ( " " ) ;
// Read from clipboard
if ( wxTheClipboard - > Open ( ) ) {
if ( wxTheClipboard - > IsSupported ( wxDF_TEXT ) ) {
wxTextDataObject rawdata ;
wxTheClipboard - > GetData ( rawdata ) ;
data = rawdata . GetText ( ) ;
}
wxTheClipboard - > Close ( ) ;
}
// Check if it actually got anything
if ( ! data . empty ( ) ) {
2006-12-17 19:30:19 +01:00
// Insert data
2006-01-16 22:02:54 +01:00
int inserted = 0 ;
2006-12-17 19:30:19 +01:00
bool asked = false ;
wxArrayInt pasteOverOptions ;
2006-01-16 22:02:54 +01:00
wxStringTokenizer token ( data , _T ( " \r \n " ) , wxTOKEN_STRTOK ) ;
while ( token . HasMoreTokens ( ) ) {
2006-12-17 19:30:19 +01:00
// Convert data into an AssDialogue
2006-01-16 22:02:54 +01:00
wxString curdata = token . GetNextToken ( ) ;
curdata . Trim ( true ) ;
curdata . Trim ( false ) ;
2006-12-17 19:30:19 +01:00
AssDialogue * curdiag ;
2006-01-16 22:02:54 +01:00
try {
2006-12-17 19:30:19 +01:00
curdiag = new AssDialogue ( curdata ) ;
2006-01-16 22:02:54 +01:00
}
catch ( . . . ) {
2006-12-17 19:30:19 +01:00
curdiag = new AssDialogue ( ) ;
curdiag - > Text = curdata ;
2006-01-16 22:02:54 +01:00
}
2006-12-17 19:30:19 +01:00
// Paste over
if ( pasteOver ) {
if ( n + inserted < GetRows ( ) ) {
// Get list of options to paste over, if not asked yet
if ( asked = = false ) {
asked = true ;
2006-12-17 20:41:52 +01:00
DialogPasteOver diag ( NULL ) ;
if ( ! diag . ShowModal ( ) ) {
delete curdiag ;
return ;
}
pasteOverOptions = diag . GetOptions ( ) ;
2006-12-17 19:30:19 +01:00
}
// Paste over
AssDialogue * target = GetDialogue ( n + inserted ) ;
if ( pasteOverOptions [ 0 ] ) target - > Layer = curdiag - > Layer ;
if ( pasteOverOptions [ 1 ] ) target - > Start = curdiag - > Start ;
if ( pasteOverOptions [ 2 ] ) target - > End = curdiag - > End ;
if ( pasteOverOptions [ 3 ] ) target - > Style = curdiag - > Style ;
if ( pasteOverOptions [ 4 ] ) target - > Actor = curdiag - > Actor ;
2007-01-05 19:27:15 +01:00
if ( pasteOverOptions [ 5 ] ) target - > Margin [ 0 ] = curdiag - > Margin [ 0 ] ;
if ( pasteOverOptions [ 6 ] ) target - > Margin [ 1 ] = curdiag - > Margin [ 1 ] ;
if ( pasteOverOptions [ 7 ] ) target - > Margin [ 2 ] = curdiag - > Margin [ 2 ] ;
2007-03-28 03:37:13 +02:00
//if (pasteOverOptions[8]) target->Margin[3] = curdiag->Margin[3];
if ( pasteOverOptions [ 8 ] ) target - > Effect = curdiag - > Effect ;
if ( pasteOverOptions [ 9 ] ) target - > Text = curdiag - > Text ;
2006-12-17 19:30:19 +01:00
}
delete curdiag ;
}
// Paste normally
else InsertLine ( curdiag , n + inserted , false , false ) ;
// Increment insertion
inserted + + ;
2006-01-16 22:02:54 +01:00
}
2006-12-17 19:30:19 +01:00
// Update data post-insertion
2006-01-16 22:02:54 +01:00
if ( inserted > 0 ) {
// Commit
2006-02-22 07:08:35 +01:00
UpdateMaps ( ) ;
2006-02-23 20:26:14 +01:00
AdjustScrollbar ( ) ;
2007-01-26 01:47:42 +01:00
ass - > FlagAsModified ( _ ( " paste " ) ) ;
2006-01-16 22:02:54 +01:00
CommitChanges ( ) ;
// Set selection
2006-12-17 19:30:19 +01:00
if ( ! pasteOver ) {
SelectRow ( n ) ;
for ( int i = n + 1 ; i < n + inserted ; i + + ) {
SelectRow ( i , true ) ;
}
editBox - > SetToLine ( n ) ;
2006-01-16 22:02:54 +01:00
}
}
}
2006-11-23 20:08:46 +01:00
2006-12-17 19:30:19 +01:00
// Done
2006-11-23 20:08:46 +01:00
EndBatch ( ) ;
2006-01-16 22:02:54 +01:00
}
/////////////////////////
// Delete selected lines
2006-02-22 07:08:35 +01:00
void SubtitlesGrid : : DeleteLines ( wxArrayInt target ) {
2006-01-16 22:02:54 +01:00
// Check if it's wiping file
int deleted = 0 ;
2006-02-22 07:08:35 +01:00
// Delete lines
int size = target . Count ( ) ;
for ( int i = 0 ; i < size ; i + + ) {
delete ( * diagMap . at ( target [ i ] ) ) ;
ass - > Line . erase ( diagMap . at ( target [ i ] ) ) ;
deleted + + ;
2006-01-16 22:02:54 +01:00
}
// Add default line if file was wiped
if ( GetRows ( ) = = deleted ) {
AssDialogue * def = new AssDialogue ;
ass - > Line . push_back ( def ) ;
}
// Update
2006-02-21 03:01:42 +01:00
UpdateMaps ( ) ;
AdjustScrollbar ( ) ;
2007-01-26 01:47:42 +01:00
ass - > FlagAsModified ( _ ( " delete " ) ) ;
2006-02-21 03:01:42 +01:00
CommitChanges ( ) ;
2006-03-01 04:17:31 +01:00
// Update editbox
editBox - > SetToLine ( MID ( 0 , editBox - > linen , GetRows ( ) - 1 ) ) ;
2006-01-16 22:02:54 +01:00
}
////////////////////////
// Joins selected lines
void SubtitlesGrid : : JoinLines ( int n1 , int n2 , bool concat ) {
// Initialize
int min_ms = 0x0FFFFFFF ;
int max_ms = - 1 ;
wxString finalText = _T ( " " ) ;
// Collect data
AssDialogue * cur ;
int start , end ;
bool gotfirst = false ;
for ( int i = n1 ; i < = n2 ; i + + ) {
2007-07-27 09:08:22 +02:00
// Get start and end time of current line
2006-01-16 22:02:54 +01:00
cur = GetDialogue ( i ) ;
start = cur - > Start . GetMS ( ) ;
end = cur - > End . GetMS ( ) ;
2007-07-27 09:08:22 +02:00
// Don't take the timing of zero lines
if ( start ! = 0 | | end ! = 0 ) {
if ( start < min_ms ) min_ms = start ;
if ( end > max_ms ) max_ms = end ;
}
// Set text
2006-01-16 22:02:54 +01:00
if ( concat | | ! gotfirst ) {
if ( gotfirst ) finalText + = _T ( " \\ N " ) ;
gotfirst = true ;
finalText + = cur - > Text ;
}
}
// Apply settings to first line
cur = GetDialogue ( n1 ) ;
cur - > Start . SetMS ( min_ms ) ;
cur - > End . SetMS ( max_ms ) ;
cur - > Text = finalText ;
cur - > UpdateData ( ) ;
// Delete remaining lines (this will auto commit)
2006-02-22 07:08:35 +01:00
DeleteLines ( GetRangeArray ( n1 + 1 , n2 ) ) ;
2006-01-16 22:02:54 +01:00
// Select new line
editBox - > SetToLine ( n1 ) ;
SelectRow ( n1 ) ;
}
//////////////////////////
// Adjoins selected lines
void SubtitlesGrid : : AdjoinLines ( int n1 , int n2 , bool setStart ) {
// Set start
if ( setStart ) {
AssDialogue * prev = GetDialogue ( n1 ) ;
AssDialogue * cur ;
for ( int i = n1 + 1 ; i < = n2 ; i + + ) {
cur = GetDialogue ( i ) ;
if ( ! cur ) return ;
cur - > Start = prev - > End ;
cur - > UpdateData ( ) ;
prev = cur ;
}
}
// Set end
else {
AssDialogue * next ;
AssDialogue * cur = GetDialogue ( n1 ) ;
for ( int i = n1 ; i < n2 ; i + + ) {
next = GetDialogue ( i + 1 ) ;
if ( ! next ) return ;
cur - > End = next - > Start ;
cur - > UpdateData ( ) ;
cur = next ;
}
}
// Commit
2007-01-26 01:47:42 +01:00
AssFile : : top - > FlagAsModified ( _ ( " adjoin " ) ) ;
2006-01-16 22:02:54 +01:00
CommitChanges ( ) ;
}
///////////////////////////////////
// Joins selected lines as karaoke
void SubtitlesGrid : : JoinAsKaraoke ( int n1 , int n2 ) {
// Initialize
wxString finalText = _T ( " " ) ;
// Collect data
AssDialogue * cur ;
int start , end ;
2007-01-11 04:18:14 +01:00
int firststart = 0 ;
2006-01-16 22:02:54 +01:00
int lastend = - 1 ;
int len1 , len2 ;
for ( int i = n1 ; i < = n2 ; i + + ) {
cur = GetDialogue ( i ) ;
// Get times
start = cur - > Start . GetMS ( ) ;
end = cur - > End . GetMS ( ) ;
// Get len
if ( lastend = = - 1 ) {
lastend = start ;
firststart = start ;
}
len1 = ( start - lastend ) / 10 ;
2006-10-20 00:53:06 +02:00
len2 = ( end - start ) / 10 ;
2006-01-16 22:02:54 +01:00
// Create text
if ( len1 ! = 0 ) finalText + = _T ( " { \\ k " ) + wxString : : Format ( _T ( " %i " ) , len1 ) + _T ( " } " ) ;
finalText + = _T ( " { \\ k " ) + wxString : : Format ( _T ( " %i " ) , len2 ) + _T ( " } " ) + cur - > Text ;
lastend = end ;
}
// Apply settings to first line
cur = GetDialogue ( n1 ) ;
cur - > Start . SetMS ( firststart ) ;
cur - > End . SetMS ( lastend ) ;
cur - > Text = finalText ;
cur - > UpdateData ( ) ;
// Delete remaining lines (this will auto commit)
2006-02-22 07:08:35 +01:00
DeleteLines ( GetRangeArray ( n1 + 1 , n2 ) ) ;
2006-01-16 22:02:54 +01:00
// Select new line
editBox - > SetToLine ( n1 ) ;
SelectRow ( n1 ) ;
}
///////////////////
// Duplicate lines
void SubtitlesGrid : : DuplicateLines ( int n1 , int n2 , bool nextFrame ) {
AssDialogue * cur ;
bool update = false ;
int step = 0 ;
for ( int i = n1 ; i < = n2 ; i + + ) {
// Create
if ( i = = n2 ) update = true ;
//cur = new AssDialogue(GetDialogue(i+step)->data);
2006-02-27 03:23:50 +01:00
cur = new AssDialogue ( GetDialogue ( i ) - > GetEntryData ( ) ) ;
2006-01-16 22:02:54 +01:00
// Shift to next frame
if ( nextFrame ) {
2006-02-24 17:45:10 +01:00
int posFrame = VFR_Output . GetFrameAtTime ( cur - > End . GetMS ( ) , false ) + 1 ;
2006-03-05 03:47:20 +01:00
cur - > Start . SetMS ( VFR_Output . GetTimeAtFrame ( posFrame , true ) ) ;
cur - > End . SetMS ( VFR_Output . GetTimeAtFrame ( posFrame , false ) ) ;
2006-01-16 22:02:54 +01:00
cur - > UpdateData ( ) ;
}
// Insert
//InsertLine(cur,n1+step,false,update);
InsertLine ( cur , n2 + step , true , update ) ;
step + + ;
}
// Select new lines
SelectRow ( n1 + step , false ) ;
for ( int i = n1 + 1 ; i < = n2 ; i + + ) {
SelectRow ( i + step , true ) ;
}
editBox - > SetToLine ( n1 + step ) ;
}
///////////////////////
// Shifts line by time
// -------------------
// Where type =
// 0: Start + End
// 1: Start
// 2: End
//
void SubtitlesGrid : : ShiftLineByTime ( int n , int len , int type ) {
AssDialogue * cur = GetDialogue ( n ) ;
// Start
if ( type ! = 2 ) cur - > Start . SetMS ( cur - > Start . GetMS ( ) + len ) ;
// End
if ( type ! = 1 ) cur - > End . SetMS ( cur - > End . GetMS ( ) + len ) ;
// Update data
cur - > UpdateData ( ) ;
}
////////////////////////
// Shifts line by frame
// -------------------
// Where type =
// 0: Start + End
// 1: Start
// 2: End
//
void SubtitlesGrid : : ShiftLineByFrames ( int n , int len , int type ) {
AssDialogue * cur = GetDialogue ( n ) ;
// Start
2006-02-24 17:45:10 +01:00
if ( type ! = 2 ) cur - > Start . SetMS ( VFR_Output . GetTimeAtFrame ( len + VFR_Output . GetFrameAtTime ( cur - > Start . GetMS ( ) , true ) , true ) ) ;
2006-01-16 22:02:54 +01:00
// End
2006-02-24 17:45:10 +01:00
if ( type ! = 1 ) cur - > End . SetMS ( VFR_Output . GetTimeAtFrame ( len + VFR_Output . GetFrameAtTime ( cur - > End . GetMS ( ) , false ) , false ) ) ;
2006-01-16 22:02:54 +01:00
// Update data
cur - > UpdateData ( ) ;
}
//////////////
// Split line
2008-01-12 23:40:04 +01:00
void SubtitlesGrid : : SplitLine ( int n , int pos , int mode , wxString textIn ) {
2006-01-16 22:02:54 +01:00
// Split
AssDialogue * n1 , * n2 ;
2008-01-12 23:40:04 +01:00
// No textIn? Get saved text
if ( textIn . IsEmpty ( ) ) {
n1 = GetDialogue ( n ) ;
n2 = new AssDialogue ( n1 - > GetEntryData ( ) ) ;
}
// Otherwise use textIn
else {
n1 = GetDialogue ( n ) ;
n1 - > Text = textIn ;
n2 = new AssDialogue ( n1 - > GetEntryData ( ) ) ;
}
2006-01-16 22:02:54 +01:00
InsertLine ( n2 , n , true , false ) ;
// Modify text
wxString orig = n1 - > Text ;
2008-01-11 20:45:15 +01:00
n1 - > Text = orig . Left ( pos ) . Trim ( true ) ; // Trim off trailing whitespace
n2 - > Text = orig . Mid ( pos ) . Trim ( false ) ; // Trim off leading whitespace
2006-01-16 22:02:54 +01:00
// Modify time
if ( mode = = 1 ) {
double splitPos = double ( pos ) / orig . Length ( ) ;
2007-01-11 04:18:14 +01:00
int splitTime = ( int ) ( ( n1 - > End . GetMS ( ) - n1 - > Start . GetMS ( ) ) * splitPos ) + n1 - > Start . GetMS ( ) ;
2006-01-16 22:02:54 +01:00
n1 - > End . SetMS ( splitTime ) ;
n2 - > Start . SetMS ( splitTime ) ;
}
// Update data
n1 - > UpdateData ( ) ;
n2 - > UpdateData ( ) ;
// Update editbox and audio
editBox - > SetToLine ( n ) ;
// Commit
2007-01-26 01:47:42 +01:00
ass - > FlagAsModified ( _ ( " split " ) ) ;
2006-01-16 22:02:54 +01:00
CommitChanges ( ) ;
}
2006-03-11 17:11:55 +01:00
//////////////////
// Split line by karaoke
// ---------------------
// Splits the line into as many new lines as there are karaoke syllables,
// timed as the syllables.
// DOES NOT FLAG AS MODIFIED OR COMMIT CHANGES
void SubtitlesGrid : : SplitLineByKaraoke ( int lineNumber ) {
AssDialogue * line = GetDialogue ( lineNumber ) ;
line - > ParseASSTags ( ) ;
AssDialogue * nl = new AssDialogue ( line - > GetEntryData ( ) ) ;
nl - > Text = _T ( " " ) ;
nl - > End = nl - > Start ;
nl - > UpdateData ( ) ;
int kcount = 0 ;
int start_time = line - > Start . GetMS ( ) ;
// copying lost of code from automation.cpp here
// maybe it should be refactored, since a similar proc is also needed in audio_karaoke ?
for ( std : : vector < AssDialogueBlock * > : : iterator block = line - > Blocks . begin ( ) ; block ! = line - > Blocks . end ( ) ; block + + ) {
switch ( ( * block ) - > type ) {
case BLOCK_BASE :
throw wxString ( _T ( " BLOCK_BASE found processing dialogue blocks. This should never happen. " ) ) ;
case BLOCK_PLAIN :
nl - > Text + = ( * block ) - > text ;
break ;
case BLOCK_DRAWING :
nl - > Text + = ( * block ) - > text ;
break ;
case BLOCK_OVERRIDE : {
bool brackets_open = false ;
std : : vector < AssOverrideTag * > & tags = ( * block ) - > GetAsOverride ( * block ) - > Tags ;
for ( std : : vector < AssOverrideTag * > : : iterator tag = tags . begin ( ) ; tag ! = tags . end ( ) ; tag + + ) {
if ( ! ( * tag ) - > Name . Mid ( 0 , 2 ) . CmpNoCase ( _T ( " \\ k " ) ) & & ( * tag ) - > IsValid ( ) ) {
// it's a karaoke tag
if ( brackets_open ) {
nl - > Text + = _T ( " } " ) ;
brackets_open = false ;
}
if ( nl - > Text = = _T ( " " ) ) {
// don't create blank lines
delete nl ;
} else {
InsertLine ( nl , lineNumber + kcount , true , false ) ;
kcount + + ;
}
nl = new AssDialogue ( line - > GetEntryData ( ) ) ;
nl - > Text = _T ( " " ) ;
nl - > Start . SetMS ( start_time ) ;
nl - > End . SetMS ( start_time + ( * tag ) - > Params [ 0 ] - > AsInt ( ) * 10 ) ;
nl - > UpdateData ( ) ;
start_time = nl - > End . GetMS ( ) ; ;
} else {
if ( ! brackets_open ) {
nl - > Text + = _T ( " { " ) ;
brackets_open = true ;
}
nl - > Text + = ( * tag ) - > ToString ( ) ;
}
}
if ( brackets_open ) {
nl - > Text + = _T ( " } " ) ;
}
break ; }
}
}
if ( nl - > Text = = _T ( " " ) ) {
// don't create blank lines
delete nl ;
} else {
InsertLine ( nl , lineNumber + kcount , true , false ) ;
kcount + + ;
}
2006-11-23 20:08:46 +01:00
// POSSIBLE BUG/LEAK! If the above code throws an exception, the blocks are never cleared!!
2006-03-11 17:11:55 +01:00
line - > ClearBlocks ( ) ;
{
wxArrayInt oia ;
oia . Add ( lineNumber ) ;
DeleteLines ( oia ) ;
}
}
2006-01-16 22:02:54 +01:00
//////////////////
// Commit changes
// --------------
2006-02-23 05:19:57 +01:00
// This will save the work .ass and refresh it
2007-01-08 06:32:29 +01:00
void SubtitlesGrid : : CommitChanges ( bool force , bool videoOnly ) {
2007-01-21 07:30:19 +01:00
if ( VideoContext : : Get ( ) - > IsLoaded ( ) | | force ) {
2006-01-16 22:02:54 +01:00
// Check if it's playing
bool playing = false ;
2007-01-21 07:30:19 +01:00
if ( VideoContext : : Get ( ) - > IsPlaying ( ) ) {
2006-01-16 22:02:54 +01:00
playing = true ;
2007-01-21 07:30:19 +01:00
VideoContext : : Get ( ) - > Stop ( ) ;
2006-01-16 22:02:54 +01:00
}
// Export
2007-01-21 07:30:19 +01:00
//wxString workfile = VideoContext::Get()->GetTempWorkFile();
//ass->Export(workfile);
2006-01-22 13:44:53 +01:00
2007-01-21 07:30:19 +01:00
// Update video
if ( VideoContext : : Get ( ) - > IsLoaded ( ) ) VideoContext : : Get ( ) - > Refresh ( false , true ) ;
2006-01-16 22:02:54 +01:00
// Resume play
2007-01-21 07:30:19 +01:00
if ( playing ) VideoContext : : Get ( ) - > Play ( ) ;
2006-01-16 22:02:54 +01:00
}
2006-12-01 00:27:59 +01:00
2007-01-08 06:32:29 +01:00
if ( ! videoOnly ) {
// Autosave if option is enabled
if ( Options . AsBool ( _T ( " Auto Save on Every Change " ) ) ) {
if ( ass - > IsModified ( ) & & ! ass - > filename . IsEmpty ( ) ) parentFrame - > SaveSubtitles ( false ) ;
}
2006-12-01 00:27:59 +01:00
2007-01-08 06:32:29 +01:00
// Update parent frame
parentFrame - > UpdateTitle ( ) ;
SetColumnWidths ( ) ;
Refresh ( false ) ;
}
2006-01-16 22:02:54 +01:00
}
2006-02-22 05:59:39 +01:00
//////////////////////////
// Set start to video pos
void SubtitlesGrid : : SetSubsToVideo ( bool start ) {
// Check if it's OK to do it
2006-06-27 21:11:41 +02:00
if ( ! VFR_Output . IsLoaded ( ) ) return ;
2006-02-22 05:59:39 +01:00
// Get new time
2007-01-21 07:30:19 +01:00
int ms = VFR_Output . GetTimeAtFrame ( VideoContext : : Get ( ) - > GetFrameN ( ) , start ) ;
2006-02-22 05:59:39 +01:00
// Update selection
wxArrayInt sel = GetSelection ( ) ;
AssDialogue * cur ;
int modified = 0 ;
for ( size_t i = 0 ; i < sel . Count ( ) ; i + + ) {
cur = GetDialogue ( sel [ i ] ) ;
if ( cur ) {
modified + + ;
if ( start ) cur - > Start . SetMS ( ms ) ;
else cur - > End . SetMS ( ms ) ;
cur - > UpdateData ( ) ;
}
}
// Commit
if ( modified ) {
2007-01-26 01:47:42 +01:00
ass - > FlagAsModified ( _ ( " timing " ) ) ;
2006-02-22 05:59:39 +01:00
CommitChanges ( ) ;
editBox - > Update ( ) ;
}
}
//////////////////////////////
// Set video pos to start/end
void SubtitlesGrid : : SetVideoToSubs ( bool start ) {
wxArrayInt sel = GetSelection ( ) ;
if ( sel . Count ( ) = = 0 ) return ;
AssDialogue * cur = GetDialogue ( sel [ 0 ] ) ;
if ( cur ) {
2006-02-24 17:45:10 +01:00
if ( start )
2007-01-21 07:30:19 +01:00
VideoContext : : Get ( ) - > JumpToFrame ( VFR_Output . GetFrameAtTime ( cur - > Start . GetMS ( ) , true ) ) ;
2006-02-24 17:45:10 +01:00
else
2007-01-21 07:30:19 +01:00
VideoContext : : Get ( ) - > JumpToFrame ( VFR_Output . GetFrameAtTime ( cur - > End . GetMS ( ) , false ) ) ;
2006-02-22 05:59:39 +01:00
}
}
2006-12-28 23:31:33 +01:00
/////////////////////////////////////////////////////////////////////
// Retrieve a list of selected lines in the actual ASS file
// (ie. not as displayed in the grid but as represented in the file)
std : : vector < int > SubtitlesGrid : : GetAbsoluteSelection ( ) {
std : : vector < int > result ;
result . reserve ( GetNumberSelection ( ) ) ;
int nrows = GetRows ( ) ;
for ( int i = 0 ; i ! = nrows ; + + i ) {
if ( selMap . at ( i ) ) {
entryIter l = diagMap . at ( i ) ;
int n = 0 ;
for ( std : : list < AssEntry * > : : iterator j = ass - > Line . begin ( ) ; j ! = ass - > Line . end ( ) ; + + j , + + n ) {
if ( j = = l ) {
result . push_back ( n ) ;
break ;
}
}
}
}
return result ;
}
2007-02-06 23:58:05 +01:00
/////////////////////////////////////////////////////////////////////
// Update list of selected lines from absolute selection
// selection vector must be sorted
void SubtitlesGrid : : SetSelectionFromAbsolute ( std : : vector < int > & selection ) {
int nrows = GetRows ( ) ;
std : : list < AssEntry * > : : iterator j = ass - > Line . begin ( ) ;
int index = 0 ;
for ( int i = 0 ; i ! = nrows ; + + i ) {
entryIter l = diagMap . at ( i ) ;
while ( j ! = l & & j ! = ass - > Line . end ( ) ) + + j , + + index ;
if ( j = = l & & binary_search ( selection . begin ( ) , selection . end ( ) , index ) ) {
selMap [ i ] = true ;
} else selMap [ i ] = false ;
}
}