forked from mia/Aegisub
76f0afecaf
A lot of the wxDialog subclasses don't actually override any virtual functions, so there's no particular need for them to be subclasses at all, and wxDialog's vtable is so huge that they actually contribute measureable to the size of the executable.
259 lines
11 KiB
C++
259 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);
|
|
}
|