2006-12-18 17:20:45 +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.
//
2009-07-29 07:43:02 +02:00
// Aegisub Project http://www.aegisub.org/
2013-04-16 02:09:21 +02:00
# include "ass_dialogue.h"
# include "ass_file.h"
2014-05-22 01:23:28 +02:00
# include "async_video_provider.h"
2013-04-16 02:09:21 +02:00
# include "compat.h"
2014-05-29 17:28:37 +02:00
# include "format.h"
2013-04-16 02:09:21 +02:00
# include "help_button.h"
# include "include/aegisub/context.h"
# include "libresrc/libresrc.h"
# include "options.h"
2014-05-22 01:23:28 +02:00
# include "project.h"
2013-04-16 02:09:21 +02:00
# include "selection_controller.h"
# include "utils.h"
2014-03-07 19:58:51 +01:00
# include <libaegisub/address_of_adaptor.h>
2014-07-06 16:28:58 +02:00
# include <libaegisub/ass/time.h>
2014-03-07 19:58:51 +01:00
2011-01-16 08:17:36 +01:00
# include <algorithm>
2014-03-07 19:58:51 +01:00
# include <boost/range/adaptor/filtered.hpp>
2013-04-16 02:09:21 +02:00
# include <boost/range/algorithm.hpp>
2014-05-23 00:40:16 +02:00
# include <boost/range/algorithm_ext/push_back.hpp>
2012-09-25 01:35:27 +02:00
# include <functional>
2014-05-22 21:07:15 +02:00
# include <vector>
2012-01-18 23:51:17 +01:00
# include <wx/button.h>
# include <wx/checkbox.h>
# include <wx/checklst.h>
2014-05-22 21:07:15 +02:00
# include <wx/dialog.h>
2011-07-16 08:42:55 +02:00
# include <wx/msgdlg.h>
2012-01-18 23:51:17 +01:00
# include <wx/sizer.h>
# include <wx/slider.h>
# include <wx/statbox.h>
2011-07-16 08:42:55 +02:00
# include <wx/stattext.h>
2012-01-18 23:51:17 +01:00
# include <wx/textctrl.h>
# include <wx/valnum.h>
2011-01-16 08:17:36 +01:00
2014-03-07 19:58:51 +01:00
using namespace boost : : adaptors ;
2012-01-18 23:51:17 +01:00
namespace {
2014-05-22 21:07:15 +02:00
/// @class DialogTimingProcessor
/// @brief Automatic postprocessor for correcting common timing issues
2014-05-31 02:05:25 +02:00
struct DialogTimingProcessor {
wxDialog d ;
2014-05-22 21:07:15 +02:00
agi : : Context * c ; ///< Project context
int leadIn ; ///< Lead-in to add in milliseconds
int leadOut ; ///< Lead-out to add in milliseconds
int beforeStart ; ///< Maximum time in milliseconds to move start time of line backwards to land on a keyframe
int afterStart ; ///< Maximum time in milliseconds to move start time of line forwards to land on a keyframe
int beforeEnd ; ///< Maximum time in milliseconds to move end time of line backwards to land on a keyframe
int afterEnd ; ///< Maximum time in milliseconds to move end time of line forwards to land on a keyframe
int adjGap ; ///< Maximum gap in milliseconds to snap adjacent lines to each other
int adjOverlap ; ///< Maximum overlap in milliseconds to snap adjacent lines to each other
wxCheckBox * onlySelection ; ///< Only process selected lines of the selected styles
wxCheckBox * hasLeadIn ; ///< Enable adding lead-in
wxCheckBox * hasLeadOut ; ///< Enable adding lead-out
wxCheckBox * keysEnable ; ///< Enable snapping to keyframes
wxCheckBox * adjsEnable ; ///< Enable snapping adjacent lines to each other
wxSlider * adjacentBias ; ///< Bias between shifting start and end times when snapping adjacent lines
wxCheckListBox * StyleList ; ///< List of styles to process
wxButton * ApplyButton ; ///< Button to apply the processing
void OnApply ( wxCommandEvent & event ) ;
/// Check or uncheck all styles
void CheckAll ( bool check ) ;
/// Enable and disable text boxes based on which checkboxes are checked
void UpdateControls ( ) ;
/// Process the file
void Process ( ) ;
/// Get a list of dialogue lines in the file sorted by start time
std : : vector < AssDialogue * > SortDialogues ( ) ;
DialogTimingProcessor ( agi : : Context * c ) ;
} ;
2012-01-18 23:51:17 +01:00
wxTextCtrl * make_ctrl ( wxWindow * parent , wxSizer * sizer , wxString const & desc , int * value , wxCheckBox * cb , wxString const & tooltip ) {
wxIntegerValidator < int > validator ( value ) ;
validator . SetMin ( 0 ) ;
wxTextCtrl * ctrl = new wxTextCtrl ( parent , - 1 , " " , wxDefaultPosition , wxSize ( 60 , - 1 ) , 0 , validator ) ;
ctrl - > SetToolTip ( tooltip ) ;
if ( ! desc . empty ( ) )
sizer - > Add ( new wxStaticText ( parent , - 1 , desc ) , wxSizerFlags ( ) . Center ( ) . Border ( wxRIGHT ) ) ;
sizer - > Add ( ctrl , wxSizerFlags ( ) . Expand ( ) . Border ( wxRIGHT ) ) ;
ctrl - > Enable ( cb - > IsChecked ( ) ) ;
2014-03-26 18:36:34 +01:00
cb - > Bind ( wxEVT_CHECKBOX , [ = ] ( wxCommandEvent & evt ) {
ctrl - > Enable ( cb - > IsChecked ( ) ) ;
evt . Skip ( ) ;
} ) ;
2012-01-18 23:51:17 +01:00
return ctrl ;
}
inline wxTextCtrl * make_ctrl ( wxStaticBoxSizer * sizer , wxString const & desc , int * value , wxCheckBox * cb , wxString const & tooltip ) {
return make_ctrl ( sizer - > GetStaticBox ( ) - > GetParent ( ) , sizer , desc , value , cb , tooltip ) ;
}
wxCheckBox * make_check ( wxStaticBoxSizer * sizer , wxString const & desc , const char * opt , wxString const & tooltip ) {
wxCheckBox * cb = new wxCheckBox ( sizer - > GetStaticBox ( ) - > GetParent ( ) , - 1 , desc ) ;
cb - > SetToolTip ( tooltip ) ;
cb - > SetValue ( OPT_GET ( opt ) - > GetBool ( ) ) ;
sizer - > Add ( cb , wxSizerFlags ( ) . Border ( wxRIGHT ) . Expand ( ) ) ;
return cb ;
}
Note: This was done using a script! it's far from perfect but 95% of the work has been done already formatting-wise.
Document all functions, class, struct, union, enum, macro, variable, typedefs. This isn't the actual document in itself but empty documentation using any old documentation if it was there.
This was done using exuberant ctags to get tag info, then a TCL script to parse/remove old comments and convert them into Doxygen-style.
Some notes:
* Anything labeled 'DOCME' needs to be documented, @param and @return have been left blank as it would be annoying to delete the 'DOCME' from every one of those.
* Some multiline comments may have been munged into single line comments
* Leave the /// comments above global variables with a space, if they're harder to read then we'll be less likey to use them.
* Enum comments can go after the enumeration itself '[value] /// comment'
* include/aegisub/*.h haven't been converted yet, this will be done in a later commit
* Some documentation blocks are in the wrong place, in the .h when it should be in the .cpp, or vice versa.
See http://devel.aegisub.org/wiki/Doxygen for some details on Doxygen and a 'style guide'.
Originally committed to SVN as r3312.
2009-07-30 00:59:22 +02:00
2011-01-16 08:17:36 +01:00
DialogTimingProcessor : : DialogTimingProcessor ( agi : : Context * c )
2014-05-31 02:05:25 +02:00
: d ( c - > parent , - 1 , _ ( " Timing Post-Processor " ) )
2011-01-16 08:17:36 +01:00
, c ( c )
2006-01-16 22:02:54 +01:00
{
2012-09-25 01:35:27 +02:00
using std : : bind ;
2012-01-18 23:51:17 +01:00
2014-05-31 02:05:25 +02:00
d . SetIcon ( GETICON ( timing_processor_toolbutton_16 ) ) ;
2007-07-05 01:09:40 +02:00
2012-01-18 23:51:17 +01:00
// Read options
2018-11-18 01:27:25 +01:00
leadIn = OPT_GET ( " Tool/Timing Post Processor/Lead/IN " ) - > GetInt ( ) ;
leadOut = OPT_GET ( " Tool/Timing Post Processor/Lead/OUT " ) - > GetInt ( ) ;
2012-01-18 23:51:17 +01:00
beforeStart = OPT_GET ( " Tool/Timing Post Processor/Threshold/Key Start Before " ) - > GetInt ( ) ;
beforeEnd = OPT_GET ( " Tool/Timing Post Processor/Threshold/Key End Before " ) - > GetInt ( ) ;
afterStart = OPT_GET ( " Tool/Timing Post Processor/Threshold/Key Start After " ) - > GetInt ( ) ;
afterEnd = OPT_GET ( " Tool/Timing Post Processor/Threshold/Key End After " ) - > GetInt ( ) ;
2012-02-02 00:59:40 +01:00
adjGap = OPT_GET ( " Tool/Timing Post Processor/Threshold/Adjacent Gap " ) - > GetInt ( ) ;
adjOverlap = OPT_GET ( " Tool/Timing Post Processor/Threshold/Adjacent Overlap " ) - > GetInt ( ) ;
2010-05-21 03:13:36 +02:00
2012-01-18 23:51:17 +01:00
// Styles box
2014-05-31 02:05:25 +02:00
auto LeftSizer = new wxStaticBoxSizer ( wxVERTICAL , & d , _ ( " Apply to styles " ) ) ;
StyleList = new wxCheckListBox ( & d , - 1 , wxDefaultPosition , wxSize ( 150 , 150 ) , to_wx ( c - > ass - > GetStyles ( ) ) ) ;
2007-08-16 01:17:42 +02:00
StyleList - > SetToolTip ( _ ( " Select styles to process. Unchecked ones will be ignored. " ) ) ;
2012-01-18 23:51:17 +01:00
2014-05-31 02:05:25 +02:00
auto all = new wxButton ( & d , - 1 , _ ( " &All " ) ) ;
2012-02-07 02:22:32 +01:00
all - > SetToolTip ( _ ( " Select all styles " ) ) ;
2012-01-18 23:51:17 +01:00
2014-05-31 02:05:25 +02:00
auto none = new wxButton ( & d , - 1 , _ ( " &None " ) ) ;
2012-02-07 02:22:32 +01:00
none - > SetToolTip ( _ ( " Deselect all styles " ) ) ;
2007-08-16 01:17:42 +02:00
2007-01-08 04:27:47 +01:00
// Options box
2014-05-31 02:05:25 +02:00
auto optionsSizer = new wxStaticBoxSizer ( wxHORIZONTAL , & d , _ ( " Options " ) ) ;
onlySelection = new wxCheckBox ( & d , - 1 , _ ( " Affect &selection only " ) ) ;
2010-05-21 03:13:36 +02:00
onlySelection - > SetValue ( OPT_GET ( " Tool/Timing Post Processor/Only Selection " ) - > GetBool ( ) ) ;
2007-01-08 04:27:47 +01:00
optionsSizer - > Add ( onlySelection , 1 , wxALL , 0 ) ;
2006-01-16 22:02:54 +01:00
// Lead-in/out box
2014-05-31 02:05:25 +02:00
auto LeadSizer = new wxStaticBoxSizer ( wxHORIZONTAL , & d , _ ( " Lead-in/Lead-out " ) ) ;
2012-01-18 23:51:17 +01:00
hasLeadIn = make_check ( LeadSizer , _ ( " Add lead &in: " ) ,
" Tool/Timing Post Processor/Enable/Lead/IN " ,
2012-02-07 02:22:32 +01:00
_ ( " Enable adding of lead-ins to lines " ) ) ;
make_ctrl ( LeadSizer , " " , & leadIn , hasLeadIn , _ ( " Lead in to be added, in milliseconds " ) ) ;
2012-01-18 23:51:17 +01:00
hasLeadOut = make_check ( LeadSizer , _ ( " Add lead &out: " ) ,
" Tool/Timing Post Processor/Enable/Lead/OUT " ,
2012-02-07 02:22:32 +01:00
_ ( " Enable adding of lead-outs to lines " ) ) ;
make_ctrl ( LeadSizer , " " , & leadOut , hasLeadOut , _ ( " Lead out to be added, in milliseconds " ) ) ;
2012-01-18 23:51:17 +01:00
2006-01-16 22:02:54 +01:00
LeadSizer - > AddStretchSpacer ( 1 ) ;
2008-01-27 23:09:47 +01:00
// Adjacent subs sizer
2014-05-31 02:05:25 +02:00
auto AdjacentSizer = new wxStaticBoxSizer ( wxHORIZONTAL , & d , _ ( " Make adjacent subtitles continuous " ) ) ;
2012-01-18 23:51:17 +01:00
adjsEnable = make_check ( AdjacentSizer , _ ( " &Enable " ) ,
" Tool/Timing Post Processor/Enable/Adjacent " ,
2012-02-07 02:22:32 +01:00
_ ( " Enable snapping of subtitles together if they are within a certain distance of each other " ) ) ;
2012-01-18 23:51:17 +01:00
2014-05-22 01:23:28 +02:00
auto adjBoxes = new wxBoxSizer ( wxHORIZONTAL ) ;
2014-05-31 02:05:25 +02:00
make_ctrl ( & d , adjBoxes , _ ( " Max gap: " ) , & adjGap , adjsEnable ,
2012-02-07 02:22:32 +01:00
_ ( " Maximum difference between start and end time for two subtitles to be made continuous, in milliseconds " ) ) ;
2014-05-31 02:05:25 +02:00
make_ctrl ( & d , adjBoxes , _ ( " Max overlap: " ) , & adjOverlap , adjsEnable ,
2012-02-07 02:22:32 +01:00
_ ( " Maximum overlap between the end and start time for two subtitles to be made continuous, in milliseconds " ) ) ;
2012-01-18 23:51:17 +01:00
2019-10-29 01:45:29 +01:00
adjacentBias = new wxSlider ( & d , - 1 , mid < int > ( 0 , OPT_GET ( " Tool/Timing Post Processor/Adjacent Bias " ) - > GetDouble ( ) * 100 , 100 ) , 0 , 100 ) ;
2012-02-02 00:59:40 +01:00
adjacentBias - > SetToolTip ( _ ( " Sets how to set the adjoining of lines. If set totally to left, it will extend or shrink start time of the second line; if totally to right, it will extend or shrink the end time of the first line. " ) ) ;
2012-01-18 23:51:17 +01:00
2014-05-22 01:23:28 +02:00
auto adjSliderSizer = new wxBoxSizer ( wxHORIZONTAL ) ;
2014-05-31 02:05:25 +02:00
adjSliderSizer - > Add ( new wxStaticText ( & d , - 1 , _ ( " Bias: Start <- " ) ) , wxSizerFlags ( ) . Center ( ) ) ;
2012-04-27 21:08:02 +02:00
adjSliderSizer - > Add ( adjacentBias , wxSizerFlags ( 1 ) . Center ( ) ) ;
2014-05-31 02:05:25 +02:00
adjSliderSizer - > Add ( new wxStaticText ( & d , - 1 , _ ( " -> End " ) ) , wxSizerFlags ( ) . Center ( ) ) ;
2012-02-02 00:59:40 +01:00
2014-05-22 01:23:28 +02:00
auto adjRightSizer = new wxBoxSizer ( wxVERTICAL ) ;
2012-04-27 21:08:02 +02:00
adjRightSizer - > Add ( adjBoxes , wxSizerFlags ( ) . Expand ( ) ) ;
adjRightSizer - > Add ( adjSliderSizer , wxSizerFlags ( ) . Expand ( ) . Border ( wxTOP ) ) ;
2012-02-02 00:59:40 +01:00
AdjacentSizer - > Add ( adjRightSizer ) ;
2006-03-17 02:27:30 +01:00
2006-01-16 22:02:54 +01:00
// Keyframes sizer
2014-05-31 02:05:25 +02:00
auto KeyframesSizer = new wxStaticBoxSizer ( wxHORIZONTAL , & d , _ ( " Keyframe snapping " ) ) ;
2014-05-22 01:23:28 +02:00
auto KeyframesFlexSizer = new wxFlexGridSizer ( 2 , 5 , 5 , 0 ) ;
2012-01-18 23:51:17 +01:00
2014-05-31 02:05:25 +02:00
keysEnable = new wxCheckBox ( & d , - 1 , _ ( " E&nable " ) ) ;
2012-02-07 02:22:32 +01:00
keysEnable - > SetToolTip ( _ ( " Enable snapping of subtitles to nearest keyframe, if distance is within threshold " ) ) ;
2010-05-21 03:13:36 +02:00
keysEnable - > SetValue ( OPT_GET ( " Tool/Timing Post Processor/Enable/Keyframe " ) - > GetBool ( ) ) ;
2006-03-21 10:24:46 +01:00
KeyframesFlexSizer - > Add ( keysEnable , 0 , wxRIGHT | wxEXPAND , 10 ) ;
2012-01-18 23:51:17 +01:00
// Keyframes are only available if timecodes are loaded
2014-05-22 01:23:28 +02:00
bool keysAvailable = ! c - > project - > Keyframes ( ) . empty ( ) & & c - > project - > Timecodes ( ) . IsLoaded ( ) ;
2012-01-18 23:51:17 +01:00
if ( ! keysAvailable ) {
keysEnable - > SetValue ( false ) ;
keysEnable - > Enable ( false ) ;
}
2014-05-31 02:05:25 +02:00
make_ctrl ( & d , KeyframesFlexSizer , _ ( " Starts before thres.: " ) , & beforeStart , keysEnable ,
2012-02-07 02:22:32 +01:00
_ ( " Threshold for 'before start' distance, that is, how many milliseconds a subtitle must start before a keyframe to snap to it " ) ) ;
2012-01-18 23:51:17 +01:00
2014-05-31 02:05:25 +02:00
make_ctrl ( & d , KeyframesFlexSizer , _ ( " Starts after thres.: " ) , & afterStart , keysEnable ,
2012-02-07 02:22:32 +01:00
_ ( " Threshold for 'after start' distance, that is, how many milliseconds a subtitle must start after a keyframe to snap to it " ) ) ;
2012-01-18 23:51:17 +01:00
2006-03-21 10:24:46 +01:00
KeyframesFlexSizer - > AddStretchSpacer ( 1 ) ;
2012-01-18 23:51:17 +01:00
2014-05-31 02:05:25 +02:00
make_ctrl ( & d , KeyframesFlexSizer , _ ( " Ends before thres.: " ) , & beforeEnd , keysEnable ,
2012-02-07 02:22:32 +01:00
_ ( " Threshold for 'before end' distance, that is, how many milliseconds a subtitle must end before a keyframe to snap to it " ) ) ;
2012-01-18 23:51:17 +01:00
2014-05-31 02:05:25 +02:00
make_ctrl ( & d , KeyframesFlexSizer , _ ( " Ends after thres.: " ) , & afterEnd , keysEnable ,
2012-02-07 02:22:32 +01:00
_ ( " Threshold for 'after end' distance, that is, how many milliseconds a subtitle must end after a keyframe to snap to it " ) ) ;
2012-01-18 23:51:17 +01:00
2006-03-21 10:24:46 +01:00
KeyframesSizer - > Add ( KeyframesFlexSizer , 0 , wxEXPAND ) ;
2006-01-16 22:02:54 +01:00
KeyframesSizer - > AddStretchSpacer ( 1 ) ;
// Button sizer
2014-05-31 02:05:25 +02:00
auto ButtonSizer = d . CreateStdDialogButtonSizer ( wxOK | wxCANCEL | wxHELP ) ;
2012-01-18 23:51:17 +01:00
ApplyButton = ButtonSizer - > GetAffirmativeButton ( ) ;
2013-12-12 03:25:13 +01:00
ButtonSizer - > GetHelpButton ( ) - > Bind ( wxEVT_BUTTON , bind ( & HelpButton : : OpenPage , " Timing Processor " ) ) ;
2006-01-16 22:02:54 +01:00
// Right Sizer
2014-05-22 01:23:28 +02:00
auto RightSizer = new wxBoxSizer ( wxVERTICAL ) ;
2007-01-08 04:27:47 +01:00
RightSizer - > Add ( optionsSizer , 0 , wxBOTTOM | wxEXPAND , 5 ) ;
2006-01-16 22:02:54 +01:00
RightSizer - > Add ( LeadSizer , 0 , wxBOTTOM | wxEXPAND , 5 ) ;
2008-01-27 23:09:47 +01:00
RightSizer - > Add ( AdjacentSizer , 0 , wxBOTTOM | wxEXPAND , 5 ) ;
2006-03-17 02:27:30 +01:00
RightSizer - > Add ( KeyframesSizer , 0 , wxBOTTOM | wxEXPAND , 5 ) ;
2006-01-16 22:02:54 +01:00
RightSizer - > AddStretchSpacer ( 1 ) ;
RightSizer - > Add ( ButtonSizer , 0 , wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND , 0 ) ;
// Style buttons sizer
2014-05-22 01:23:28 +02:00
auto StyleButtonsSizer = new wxBoxSizer ( wxHORIZONTAL ) ;
2006-01-16 22:02:54 +01:00
StyleButtonsSizer - > Add ( all , 1 , 0 , 0 ) ;
StyleButtonsSizer - > Add ( none , 1 , 0 , 0 ) ;
// Left sizer
2012-01-18 23:51:17 +01:00
LeftSizer - > Add ( StyleList , wxSizerFlags ( 1 ) . Border ( wxBOTTOM ) ) ;
LeftSizer - > Add ( StyleButtonsSizer , wxSizerFlags ( ) . Expand ( ) ) ;
2006-01-16 22:02:54 +01:00
// Top Sizer
2014-05-22 01:23:28 +02:00
auto TopSizer = new wxBoxSizer ( wxHORIZONTAL ) ;
2006-01-16 22:02:54 +01:00
TopSizer - > Add ( LeftSizer , 0 , wxRIGHT | wxEXPAND , 5 ) ;
TopSizer - > Add ( RightSizer , 1 , wxALL | wxEXPAND , 0 ) ;
// Main Sizer
2014-05-22 01:23:28 +02:00
auto MainSizer = new wxBoxSizer ( wxVERTICAL ) ;
2006-01-16 22:02:54 +01:00
MainSizer - > Add ( TopSizer , 1 , wxALL | wxEXPAND , 5 ) ;
2014-05-31 02:05:25 +02:00
d . SetSizerAndFit ( MainSizer ) ;
d . CenterOnParent ( ) ;
2006-01-27 01:48:59 +01:00
2014-05-31 02:05:25 +02:00
d . Bind ( wxEVT_CHECKBOX , bind ( & DialogTimingProcessor : : UpdateControls , this ) ) ;
d . Bind ( wxEVT_CHECKLISTBOX , bind ( & DialogTimingProcessor : : UpdateControls , this ) ) ;
d . Bind ( wxEVT_BUTTON , & DialogTimingProcessor : : OnApply , this , wxID_OK ) ;
2013-12-12 03:25:13 +01:00
all - > Bind ( wxEVT_BUTTON , bind ( & DialogTimingProcessor : : CheckAll , this , true ) ) ;
none - > Bind ( wxEVT_BUTTON , bind ( & DialogTimingProcessor : : CheckAll , this , false ) ) ;
2006-01-16 22:02:54 +01:00
2012-01-18 23:51:17 +01:00
CheckAll ( true ) ;
2006-01-16 22:02:54 +01:00
}
2012-01-18 23:51:17 +01:00
void DialogTimingProcessor : : CheckAll ( bool value ) {
size_t count = StyleList - > GetCount ( ) ;
for ( size_t i = 0 ; i < count ; + + i )
StyleList - > Check ( i , value ) ;
2006-01-16 22:02:54 +01:00
UpdateControls ( ) ;
}
2012-01-18 23:51:17 +01:00
void DialogTimingProcessor : : UpdateControls ( ) {
// Only enable the OK button if it'll actually do something
bool any_checked = false ;
2006-01-16 22:02:54 +01:00
size_t len = StyleList - > GetCount ( ) ;
2013-04-16 02:09:21 +02:00
for ( size_t i = 0 ; ! any_checked & & i < len ; + + i )
any_checked = StyleList - > IsChecked ( i ) ;
2012-01-18 23:51:17 +01:00
ApplyButton - > Enable ( any_checked & & ( hasLeadIn - > IsChecked ( ) | | hasLeadOut - > IsChecked ( ) | | keysEnable - > IsChecked ( ) | | adjsEnable - > IsChecked ( ) ) ) ;
2006-01-16 22:02:54 +01:00
}
2010-07-08 06:29:04 +02:00
void DialogTimingProcessor : : OnApply ( wxCommandEvent & ) {
2014-05-31 02:05:25 +02:00
d . TransferDataFromWindow ( ) ;
2006-01-16 22:02:54 +01:00
// Save settings
2018-11-18 01:27:25 +01:00
OPT_SET ( " Tool/Timing Post Processor/Lead/IN " ) - > SetInt ( leadIn ) ;
OPT_SET ( " Tool/Timing Post Processor/Lead/OUT " ) - > SetInt ( leadOut ) ;
2012-01-18 23:51:17 +01:00
OPT_SET ( " Tool/Timing Post Processor/Threshold/Key Start Before " ) - > SetInt ( beforeStart ) ;
OPT_SET ( " Tool/Timing Post Processor/Threshold/Key Start After " ) - > SetInt ( afterStart ) ;
OPT_SET ( " Tool/Timing Post Processor/Threshold/Key End Before " ) - > SetInt ( beforeEnd ) ;
OPT_SET ( " Tool/Timing Post Processor/Threshold/Key End After " ) - > SetInt ( afterEnd ) ;
2012-02-02 00:59:40 +01:00
OPT_SET ( " Tool/Timing Post Processor/Threshold/Adjacent Gap " ) - > SetInt ( adjGap ) ;
OPT_SET ( " Tool/Timing Post Processor/Threshold/Adjacent Overlap " ) - > SetInt ( adjOverlap ) ;
2010-05-21 03:13:36 +02:00
OPT_SET ( " Tool/Timing Post Processor/Adjacent Bias " ) - > SetDouble ( adjacentBias - > GetValue ( ) / 100.0 ) ;
OPT_SET ( " Tool/Timing Post Processor/Enable/Lead/IN " ) - > SetBool ( hasLeadIn - > IsChecked ( ) ) ;
OPT_SET ( " Tool/Timing Post Processor/Enable/Lead/OUT " ) - > SetBool ( hasLeadOut - > IsChecked ( ) ) ;
if ( keysEnable - > IsEnabled ( ) ) OPT_SET ( " Tool/Timing Post Processor/Enable/Keyframe " ) - > SetBool ( keysEnable - > IsChecked ( ) ) ;
OPT_SET ( " Tool/Timing Post Processor/Enable/Adjacent " ) - > SetBool ( adjsEnable - > IsChecked ( ) ) ;
OPT_SET ( " Tool/Timing Post Processor/Only Selection " ) - > SetBool ( onlySelection - > IsChecked ( ) ) ;
2006-01-16 22:02:54 +01:00
2011-01-16 08:17:36 +01:00
Process ( ) ;
2014-05-31 02:05:25 +02:00
d . EndModal ( 0 ) ;
2006-01-16 22:02:54 +01:00
}
2012-01-18 23:51:17 +01:00
std : : vector < AssDialogue * > DialogTimingProcessor : : SortDialogues ( ) {
2014-05-22 01:23:28 +02:00
std : : set < boost : : flyweight < std : : string > > styles ;
2011-01-16 08:17:36 +01:00
for ( size_t i = 0 ; i < StyleList - > GetCount ( ) ; + + i ) {
2012-01-18 23:51:17 +01:00
if ( StyleList - > IsChecked ( i ) )
2014-05-22 01:23:28 +02:00
styles . insert ( boost : : flyweight < std : : string > ( from_wx ( StyleList - > GetString ( i ) ) ) ) ;
2006-01-16 22:02:54 +01:00
}
2012-01-18 23:51:17 +01:00
std : : vector < AssDialogue * > sorted ;
2014-03-07 19:58:51 +01:00
auto valid_line = [ & ] ( const AssDialogue * d ) { return ! d - > Comment & & styles . count ( d - > Style ) ; } ;
if ( onlySelection - > IsChecked ( ) )
boost : : copy ( c - > selectionController - > GetSelectedSet ( ) | filtered ( valid_line ) ,
back_inserter ( sorted ) ) ;
2011-01-16 08:17:36 +01:00
else {
2014-03-07 19:58:51 +01:00
sorted . reserve ( c - > ass - > Events . size ( ) ) ;
boost : : push_back ( sorted , c - > ass - > Events | agi : : address_of | filtered ( valid_line ) ) ;
2006-01-16 22:02:54 +01:00
}
2012-01-18 23:51:17 +01:00
// Check if rows are valid
2013-04-16 02:09:21 +02:00
for ( auto diag : sorted ) {
if ( diag - > Start > diag - > End ) {
2012-01-18 23:51:17 +01:00
wxMessageBox (
2014-05-29 17:28:37 +02:00
fmt_tl ( " One of the lines in the file (%i) has negative duration. Aborting. " , diag - > Row ) ,
2012-01-18 23:51:17 +01:00
_ ( " Invalid script " ) ,
2012-03-29 01:59:19 +02:00
wxOK | wxICON_ERROR | wxCENTER ) ;
2012-01-18 23:51:17 +01:00
sorted . clear ( ) ;
break ;
}
}
2014-03-07 19:58:51 +01:00
boost : : sort ( sorted , [ ] ( const AssDialogue * a , const AssDialogue * b ) {
return a - > Start < b - > Start ;
} ) ;
2012-01-18 23:51:17 +01:00
return sorted ;
}
static int get_closest_kf ( std : : vector < int > const & kf , int frame ) {
2013-04-16 02:09:21 +02:00
const auto pos = boost : : upper_bound ( kf , frame ) ;
2012-01-24 02:28:26 +01:00
// Return last keyframe if this is after the last one
2013-04-16 02:09:21 +02:00
if ( pos = = end ( kf ) ) return kf . back ( ) ;
2012-01-24 02:28:26 +01:00
// *pos is greater than frame, and *(pos - 1) is less than or equal to frame
2013-04-16 02:09:21 +02:00
return ( pos = = begin ( kf ) | | * pos - frame < frame - * ( pos - 1 ) ) ? * pos : * ( pos - 1 ) ;
2012-01-18 23:51:17 +01:00
}
template < class Iter , class Field >
static int safe_time ( Iter begin , Iter end , AssDialogue * comp , int initial , Field field , int const & ( * cmp ) ( int const & , int const & ) ) {
// Compare to every previous line (yay for O(n^2)!) to see if it's OK to add lead-in
for ( ; begin ! = end ; + + begin ) {
// If the line doesn't already collide with this line, extend it only
// to the edge of the line
if ( ! comp - > CollidesWith ( * begin ) )
initial = cmp ( initial , ( * begin ) - > * field ) ;
}
return initial ;
2006-01-16 22:02:54 +01:00
}
void DialogTimingProcessor : : Process ( ) {
2012-01-18 23:51:17 +01:00
std : : vector < AssDialogue * > sorted = SortDialogues ( ) ;
if ( sorted . empty ( ) ) return ;
2006-01-16 22:02:54 +01:00
// Add lead-in/out
2012-05-01 04:49:38 +02:00
if ( hasLeadIn - > IsChecked ( ) & & leadIn ) {
for ( size_t i = 0 ; i < sorted . size ( ) ; + + i )
sorted [ i ] - > Start = safe_time ( sorted . rend ( ) - i , sorted . rend ( ) ,
sorted [ i ] , sorted [ i ] - > Start - leadIn ,
& AssDialogue : : End , & std : : max < int > ) ;
}
2006-01-16 22:02:54 +01:00
2012-05-01 04:49:38 +02:00
if ( hasLeadOut - > IsChecked ( ) & & leadOut ) {
for ( size_t i = 0 ; i < sorted . size ( ) ; + + i )
sorted [ i ] - > End = safe_time ( sorted . begin ( ) + i + 1 , sorted . end ( ) ,
sorted [ i ] , sorted [ i ] - > End + leadOut ,
& AssDialogue : : Start , & std : : min < int > ) ;
2006-01-16 22:02:54 +01:00
}
2008-01-27 23:09:47 +01:00
// Make adjacent
2006-01-16 22:02:54 +01:00
if ( adjsEnable - > IsChecked ( ) ) {
2012-01-18 23:51:17 +01:00
double bias = adjacentBias - > GetValue ( ) / 100.0 ;
2006-03-05 03:25:12 +01:00
2012-01-18 23:51:17 +01:00
for ( size_t i = 1 ; i < sorted . size ( ) ; + + i ) {
AssDialogue * prev = sorted [ i - 1 ] ;
AssDialogue * cur = sorted [ i ] ;
2006-01-16 22:02:54 +01:00
2020-07-04 11:22:14 +02:00
// Raw millisecond values are used in this step instead of the typical centisecond.
// In this step, we need to distinguish between gap and overlap, as they have different thresholds.
// A small gap / overlap less than 1 centisecond may not be distinguishable using rounded centisecond values.
int dist = cur - > Start . GetMillisecond ( ) - prev - > End . GetMillisecond ( ) ;
2012-02-02 00:59:40 +01:00
if ( ( dist < 0 & & - dist < = adjOverlap ) | | ( dist > 0 & & dist < = adjGap ) ) {
2020-07-04 11:22:14 +02:00
int setPos = prev - > End . GetMillisecond ( ) + int ( dist * bias + 0.5 ) ;
2011-12-22 22:28:51 +01:00
cur - > Start = setPos ;
prev - > End = setPos ;
2006-01-16 22:02:54 +01:00
}
}
}
// Keyframe snapping
if ( keysEnable - > IsChecked ( ) ) {
2014-05-22 01:23:28 +02:00
std : : vector < int > kf = c - > project - > Keyframes ( ) ;
auto fps = c - > project - > Timecodes ( ) ;
if ( auto provider = c - > project - > VideoProvider ( ) )
kf . push_back ( provider - > GetFrameCount ( ) - 1 ) ;
2012-01-18 23:51:17 +01:00
2013-11-21 18:13:36 +01:00
for ( AssDialogue * cur : sorted ) {
2006-01-16 22:02:54 +01:00
// Get start/end frames
2014-05-22 01:23:28 +02:00
int startF = fps . FrameAtTime ( cur - > Start , agi : : vfr : : START ) ;
int endF = fps . FrameAtTime ( cur - > End , agi : : vfr : : END ) ;
2006-01-16 22:02:54 +01:00
// Get closest for start
2012-01-18 23:51:17 +01:00
int closest = get_closest_kf ( kf , startF ) ;
2014-05-22 01:23:28 +02:00
int time = fps . TimeAtFrame ( closest , agi : : vfr : : START ) ;
if ( ( closest > startF & & time - cur - > Start < = beforeStart ) | | ( closest < startF & & cur - > Start - time < = afterStart ) )
2012-01-18 23:51:28 +01:00
cur - > Start = time ;
2006-01-16 22:02:54 +01:00
// Get closest for end
2012-01-18 23:51:17 +01:00
closest = get_closest_kf ( kf , endF ) - 1 ;
2014-05-22 01:23:28 +02:00
time = fps . TimeAtFrame ( closest , agi : : vfr : : END ) ;
if ( ( closest > endF & & time - cur - > End < = beforeEnd ) | | ( closest < endF & & cur - > End - time < = afterEnd ) )
2012-01-18 23:51:28 +01:00
cur - > End = time ;
2006-01-16 22:02:54 +01:00
}
}
2011-09-15 07:16:32 +02:00
c - > ass - > Commit ( _ ( " timing processor " ) , AssFile : : COMMIT_DIAG_TIME ) ;
2006-01-16 22:02:54 +01:00
}
2014-05-22 21:07:15 +02:00
}
void ShowTimingProcessorDialog ( agi : : Context * c ) {
2014-05-31 02:05:25 +02:00
DialogTimingProcessor ( c ) . d . ShowModal ( ) ;
2014-05-23 00:40:16 +02:00
}