mirror of https://github.com/odrling/Aegisub
260 lines
11 KiB
C++
260 lines
11 KiB
C++
// Copyright (c) 2011 Niels Martin Hansen <nielsm@aegisub.org>
|
|
// Copyright (c) 2012 Thomas Goyne <plorkyeran@aegisub.org>
|
|
//
|
|
// Permission to use, copy, modify, and distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
//
|
|
// Aegisub Project http://www.aegisub.org/
|
|
|
|
/// @file dialog_export_ebu3264.cpp
|
|
/// @see dialog_export_ebu3264.h
|
|
/// @ingroup subtitle_io export
|
|
|
|
#include "dialog_export_ebu3264.h"
|
|
|
|
#include "compat.h"
|
|
#include "format.h"
|
|
#include "options.h"
|
|
|
|
#include <libaegisub/charset_conv.h>
|
|
#include <libaegisub/make_unique.h>
|
|
|
|
#include <boost/lexical_cast.hpp>
|
|
#include <boost/regex.hpp>
|
|
|
|
#include <wx/checkbox.h>
|
|
#include <wx/combobox.h>
|
|
#include <wx/dialog.h>
|
|
#include <wx/msgdlg.h>
|
|
#include <wx/radiobox.h>
|
|
#include <wx/sizer.h>
|
|
#include <wx/spinctrl.h>
|
|
#include <wx/statbox.h>
|
|
#include <wx/stattext.h>
|
|
#include <wx/textctrl.h>
|
|
#include <wx/valgen.h>
|
|
|
|
namespace {
|
|
const boost::regex timecode_regex("([[:digit:]]{2}):([[:digit:]]{2}):([[:digit:]]{2}):([[:digit:]]{2})");
|
|
|
|
/// Validator for SMPTE timecodes
|
|
class TimecodeValidator final : public wxValidator {
|
|
EbuTimecode *value;
|
|
|
|
wxTextCtrl *GetCtrl() const { return dynamic_cast<wxTextCtrl*>(GetWindow()); }
|
|
|
|
bool TransferToWindow() override {
|
|
wxTextCtrl *ctrl = GetCtrl();
|
|
if (!ctrl) return false;
|
|
ctrl->SetValue(fmt_wx("%02d:%02d:%02d:%02d", value->h, value->m, value->s, value->f));
|
|
return true;
|
|
}
|
|
|
|
bool TransferFromWindow() override {
|
|
wxTextCtrl *ctrl = GetCtrl();
|
|
if (!ctrl) return false;
|
|
|
|
std::string str = from_wx(ctrl->GetValue());
|
|
boost::smatch result;
|
|
if (!regex_match(str, result, timecode_regex))
|
|
return false;
|
|
|
|
value->h = boost::lexical_cast<int>(result.str(1));
|
|
value->m = boost::lexical_cast<int>(result.str(2));
|
|
value->s = boost::lexical_cast<int>(result.str(3));
|
|
value->f = boost::lexical_cast<int>(result.str(4));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Validate(wxWindow *parent) override {
|
|
wxTextCtrl *ctrl = GetCtrl();
|
|
if (!ctrl) return false;
|
|
|
|
if (!regex_match(from_wx(ctrl->GetValue()), timecode_regex)) {
|
|
wxMessageBox(_("Time code offset in incorrect format. Ensure it is entered as four groups of two digits separated by colons."), _("EBU STL export"), wxICON_EXCLAMATION);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
wxObject *Clone() const override { return new TimecodeValidator(*this); }
|
|
|
|
public:
|
|
TimecodeValidator(EbuTimecode *target) : value(target) { assert(target); }
|
|
TimecodeValidator(TimecodeValidator const& other) : wxValidator(other), value(other.value) { }
|
|
};
|
|
|
|
} // namespace {
|
|
|
|
int ShowEbuExportConfigurationDialog(wxWindow *owner, EbuExportSettings &s) {
|
|
wxDialog d(owner, -1, _("Export to EBU STL format"));
|
|
|
|
wxString tv_standards[] = {
|
|
_("23.976 fps (non-standard, STL24.01)"),
|
|
_("24 fps (non-standard, STL24.01)"),
|
|
_("25 fps (STL25.01)"),
|
|
_("29.97 fps (non-dropframe, STL30.01)"),
|
|
_("29.97 fps (dropframe, STL30.01)"),
|
|
_("30 fps (STL30.01)")
|
|
};
|
|
wxRadioBox *tv_standard_box = new wxRadioBox(&d, -1, _("TV standard"), wxDefaultPosition, wxDefaultSize, 6, tv_standards, 0, wxRA_SPECIFY_ROWS);
|
|
|
|
wxTextCtrl *timecode_offset_entry = new wxTextCtrl(&d, -1, "00:00:00:00");
|
|
wxCheckBox *inclusive_end_times_check = new wxCheckBox(&d, -1, _("Out-times are inclusive"));
|
|
|
|
wxString text_encodings[] = {
|
|
_("ISO 6937-2 (Latin/Western Europe)"),
|
|
_("ISO 8859-5 (Cyrillic)"),
|
|
_("ISO 8859-6 (Arabic)"),
|
|
_("ISO 8859-7 (Greek)"),
|
|
_("ISO 8859-8 (Hebrew)"),
|
|
_("UTF-8 Unicode (non-standard)")
|
|
};
|
|
wxRadioBox *text_encoding_box = new wxRadioBox(&d, -1, _("Text encoding"), wxDefaultPosition, wxDefaultSize, 6, text_encodings, 0, wxRA_SPECIFY_ROWS);
|
|
|
|
wxString wrap_modes[] = {
|
|
_("Automatically wrap long lines (ASS)"),
|
|
_("Automatically wrap long lines (Balanced)"),
|
|
_("Abort if any lines are too long"),
|
|
_("Skip lines that are too long")
|
|
};
|
|
|
|
wxSpinCtrl *max_line_length_ctrl = new wxSpinCtrl(&d, -1, wxString(), wxDefaultPosition, wxSize(65, -1));
|
|
wxComboBox *wrap_mode_ctrl = new wxComboBox(&d, -1, wrap_modes[0], wxDefaultPosition, wxDefaultSize, 4, wrap_modes, wxCB_DROPDOWN | wxCB_READONLY);
|
|
wxCheckBox *translate_alignments_check = new wxCheckBox(&d, -1, _("Translate alignments"));
|
|
|
|
max_line_length_ctrl->SetRange(10, 99);
|
|
|
|
wxString display_standards[] = {
|
|
_("Open subtitles"),
|
|
_("Level-1 teletext"),
|
|
_("Level-2 teletext")
|
|
};
|
|
|
|
wxComboBox *display_standard_ctrl = new wxComboBox(&d, -1, "", wxDefaultPosition, wxDefaultSize, 2, display_standards, wxCB_DROPDOWN | wxCB_READONLY);
|
|
|
|
wxSizer *max_line_length_labelled = new wxBoxSizer(wxHORIZONTAL);
|
|
max_line_length_labelled->Add(new wxStaticText(&d, -1, _("Max. line length:")), 1, wxALIGN_CENTRE|wxRIGHT, 12);
|
|
max_line_length_labelled->Add(max_line_length_ctrl, 0, 0, 0);
|
|
|
|
wxSizer *timecode_offset_labelled = new wxBoxSizer(wxHORIZONTAL);
|
|
timecode_offset_labelled->Add(new wxStaticText(&d, -1, _("Time code offset:")), 1, wxALIGN_CENTRE|wxRIGHT, 12);
|
|
timecode_offset_labelled->Add(timecode_offset_entry, 0, 0, 0);
|
|
|
|
wxSizer *text_formatting_sizer = new wxStaticBoxSizer(wxVERTICAL, &d, _("Text formatting"));
|
|
text_formatting_sizer->Add(max_line_length_labelled, 0, wxEXPAND | (wxALL & ~wxTOP), 6);
|
|
text_formatting_sizer->Add(wrap_mode_ctrl, 0, wxEXPAND | (wxALL & ~wxTOP), 6);
|
|
text_formatting_sizer->Add(translate_alignments_check, 0, wxEXPAND | (wxALL & ~wxTOP), 6);
|
|
|
|
wxSizer *timecode_control_sizer = new wxStaticBoxSizer(wxVERTICAL, &d, _("Time codes"));
|
|
timecode_control_sizer->Add(timecode_offset_labelled, 0, wxEXPAND | (wxALL & ~wxTOP), 6);
|
|
timecode_control_sizer->Add(inclusive_end_times_check, 0, wxEXPAND | (wxALL & ~wxTOP), 6);
|
|
|
|
wxSizer *display_standard_sizer = new wxStaticBoxSizer(wxVERTICAL, &d, _("Display standard"));
|
|
display_standard_sizer->Add(display_standard_ctrl, 0, wxEXPAND | (wxALL & ~wxTOP), 6);
|
|
|
|
wxSizer *left_column = new wxBoxSizer(wxVERTICAL);
|
|
left_column->Add(tv_standard_box, 0, wxEXPAND | wxBOTTOM, 6);
|
|
left_column->Add(timecode_control_sizer, 0, wxEXPAND | wxBOTTOM, 6);
|
|
left_column->Add(display_standard_sizer, 0, wxEXPAND, 0);
|
|
|
|
wxSizer *right_column = new wxBoxSizer(wxVERTICAL);
|
|
right_column->Add(text_encoding_box, 0, wxEXPAND|wxBOTTOM, 6);
|
|
right_column->Add(text_formatting_sizer, 0, wxEXPAND, 0);
|
|
|
|
wxSizer *vertical_split_sizer = new wxBoxSizer(wxHORIZONTAL);
|
|
vertical_split_sizer->Add(left_column, 0, wxRIGHT, 6);
|
|
vertical_split_sizer->Add(right_column, 0, 0, 0);
|
|
|
|
wxSizer *buttons_sizer = new wxBoxSizer(wxHORIZONTAL);
|
|
// Developers are requested to leave &d message in! Intentionally not translatable.
|
|
wxStaticText *sponsor_label = new wxStaticText(&d, -1, "EBU STL format writing sponsored by Bandai");
|
|
sponsor_label->Enable(false);
|
|
buttons_sizer->Add(sponsor_label, 1, wxALIGN_BOTTOM, 0);
|
|
buttons_sizer->Add(d.CreateStdDialogButtonSizer(wxOK | wxCANCEL), 0, wxLEFT, 6);
|
|
|
|
wxSizer *main_sizer = new wxBoxSizer(wxVERTICAL);
|
|
main_sizer->Add(vertical_split_sizer, 0, wxEXPAND|wxALL, 12);
|
|
main_sizer->Add(buttons_sizer, 0, wxEXPAND | (wxALL & ~wxTOP), 12);
|
|
|
|
d.SetSizerAndFit(main_sizer);
|
|
d.CenterOnParent();
|
|
|
|
// set up validators to move data in and out
|
|
tv_standard_box->SetValidator(wxGenericValidator((int*)&s.tv_standard));
|
|
text_encoding_box->SetValidator(wxGenericValidator((int*)&s.text_encoding));
|
|
translate_alignments_check->SetValidator(wxGenericValidator(&s.translate_alignments));
|
|
max_line_length_ctrl->SetValidator(wxGenericValidator(&s.max_line_length));
|
|
wrap_mode_ctrl->SetValidator(wxGenericValidator((int*)&s.line_wrapping_mode));
|
|
inclusive_end_times_check->SetValidator(wxGenericValidator(&s.inclusive_end_times));
|
|
timecode_offset_entry->SetValidator(TimecodeValidator(&s.timecode_offset));
|
|
display_standard_ctrl->SetValidator(wxGenericValidator((int*)&s.display_standard));
|
|
|
|
return d.ShowModal();
|
|
}
|
|
|
|
agi::vfr::Framerate EbuExportSettings::GetFramerate() const {
|
|
switch (tv_standard) {
|
|
case STL24: return agi::vfr::Framerate(24, 1);
|
|
case STL25: return agi::vfr::Framerate(25, 1);
|
|
case STL30: return agi::vfr::Framerate(30, 1);
|
|
case STL23: return agi::vfr::Framerate(24000, 1001, false);
|
|
case STL29: return agi::vfr::Framerate(30000, 1001, false);
|
|
case STL29drop: return agi::vfr::Framerate(30000, 1001);
|
|
default: return agi::vfr::Framerate(25, 1);
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<agi::charset::IconvWrapper> EbuExportSettings::GetTextEncoder() const {
|
|
using namespace agi;
|
|
switch (text_encoding) {
|
|
case iso6937_2: return make_unique<charset::IconvWrapper>("utf-8", "ISO-6937-2");
|
|
case iso8859_5: return make_unique<charset::IconvWrapper>("utf-8", "ISO-8859-5");
|
|
case iso8859_6: return make_unique<charset::IconvWrapper>("utf-8", "ISO-8859-6");
|
|
case iso8859_7: return make_unique<charset::IconvWrapper>("utf-8", "ISO-8859-7");
|
|
case iso8859_8: return make_unique<charset::IconvWrapper>("utf-8", "ISO-8859-8");
|
|
case utf8: return make_unique<charset::IconvWrapper>("utf-8", "utf-8");
|
|
default: return make_unique<charset::IconvWrapper>("utf-8", "ISO-8859-1");
|
|
}
|
|
}
|
|
|
|
EbuExportSettings::EbuExportSettings(std::string const& prefix)
|
|
: prefix(prefix)
|
|
, tv_standard((TvStandard)OPT_GET(prefix + "/TV Standard")->GetInt())
|
|
, text_encoding((TextEncoding)OPT_GET(prefix + "/Text Encoding")->GetInt())
|
|
, max_line_length(OPT_GET(prefix + "/Max Line Length")->GetInt())
|
|
, line_wrapping_mode((LineWrappingMode)OPT_GET(prefix + "/Line Wrapping Mode")->GetInt())
|
|
, translate_alignments(OPT_GET(prefix + "/Translate Alignments")->GetBool())
|
|
, inclusive_end_times(OPT_GET(prefix + "/Inclusive End Times")->GetBool())
|
|
, display_standard((DisplayStandard)OPT_GET(prefix + "/Display Standard")->GetInt())
|
|
{
|
|
timecode_offset.h = OPT_GET(prefix + "/Timecode Offset/H")->GetInt();
|
|
timecode_offset.m = OPT_GET(prefix + "/Timecode Offset/M")->GetInt();
|
|
timecode_offset.s = OPT_GET(prefix + "/Timecode Offset/S")->GetInt();
|
|
timecode_offset.f = OPT_GET(prefix + "/Timecode Offset/F")->GetInt();
|
|
}
|
|
|
|
void EbuExportSettings::Save() const {
|
|
OPT_SET(prefix + "/TV Standard")->SetInt(tv_standard);
|
|
OPT_SET(prefix + "/Text Encoding")->SetInt(text_encoding);
|
|
OPT_SET(prefix + "/Max Line Length")->SetInt(max_line_length);
|
|
OPT_SET(prefix + "/Line Wrapping Mode")->SetInt(line_wrapping_mode);
|
|
OPT_SET(prefix + "/Translate Alignments")->SetBool(translate_alignments);
|
|
OPT_SET(prefix + "/Inclusive End Times")->SetBool(inclusive_end_times);
|
|
OPT_SET(prefix + "/Display Standard")->SetInt(display_standard);
|
|
OPT_SET(prefix + "/Timecode Offset/H")->SetInt(timecode_offset.h);
|
|
OPT_SET(prefix + "/Timecode Offset/M")->SetInt(timecode_offset.m);
|
|
OPT_SET(prefix + "/Timecode Offset/S")->SetInt(timecode_offset.s);
|
|
OPT_SET(prefix + "/Timecode Offset/F")->SetInt(timecode_offset.f);
|
|
}
|