#include "film_editor.h"
#include "film_viewer.h"
#include "fonts_dialog.h"
+#include "language_tag_widget.h"
#include "static_text.h"
#include "subtitle_appearance_dialog.h"
#include "text_panel.h"
#include "text_view.h"
+#include "wx_ptr.h"
#include "wx_util.h"
#include "lib/analyse_subtitles_job.h"
#include "lib/dcp_content.h"
#include "lib/ffmpeg_content.h"
#include "lib/ffmpeg_subtitle_stream.h"
#include "lib/job_manager.h"
+#include "lib/scope_guard.h"
#include "lib/string_text_file_content.h"
#include "lib/string_text_file_decoder.h"
#include "lib/subtitle_analysis.h"
#include "lib/text_content.h"
+#include <dcp/warnings.h>
+LIBDCP_DISABLE_WARNINGS
#include <wx/spinctrl.h>
+LIBDCP_ENABLE_WARNINGS
-using std::vector;
-using std::string;
-using std::list;
using std::cout;
-using std::shared_ptr;
-using boost::optional;
using std::dynamic_pointer_cast;
+using std::list;
+using std::shared_ptr;
+using std::string;
+using std::vector;
using boost::bind;
+using boost::optional;
/** @param t Original text type of the content, if known */
TextPanel::TextPanel (ContentPanel* p, TextType t)
: ContentSubPanel (p, std_to_wx(text_type_to_name(t)))
- , _outline_subtitles (0)
- , _dcp_track_label (0)
- , _dcp_track (0)
- , _text_view (0)
- , _fonts_dialog (0)
, _original_type (t)
- , _loading_analysis (false)
+{
+
+}
+
+
+void
+TextPanel::create ()
{
wxString refer = _("Use this DCP's subtitle as OV and make VF");
- if (t == TextType::CLOSED_CAPTION) {
+ if (_original_type == TextType::CLOSED_CAPTION) {
refer = _("Use this DCP's closed caption as OV and make VF");
}
_burn = new CheckBox (this, _("Burn subtitles into image"));
-#ifdef __WXGTK3__
- int const spin_width = 118;
-#else
- int const spin_width = 56;
-#endif
-
_offset_label = create_label (this, _("Offset"), true);
_x_offset_label = create_label (this, _("X"), true);
- _x_offset = new SpinCtrl (this, spin_width);
+ _x_offset = new SpinCtrl (this, DCPOMATIC_SPIN_CTRL_WIDTH);
_x_offset_pc_label = new StaticText (this, _("%"));
_y_offset_label = create_label (this, _("Y"), true);
- _y_offset = new SpinCtrl (this, spin_width);
+ _y_offset = new SpinCtrl (this, DCPOMATIC_SPIN_CTRL_WIDTH);
_y_offset_pc_label = new StaticText (this, _("%"));
_scale_label = create_label (this, _("Scale"), true);
_x_scale_label = create_label (this, _("X"), true);
- _x_scale = new SpinCtrl (this, spin_width);
+ _x_scale = new SpinCtrl (this, DCPOMATIC_SPIN_CTRL_WIDTH);
_x_scale_pc_label = new StaticText (this, _("%"));
_y_scale_label = create_label (this, S_("Coord|Y"), true);
- _y_scale = new SpinCtrl (this, spin_width);
+ _y_scale = new SpinCtrl (this, DCPOMATIC_SPIN_CTRL_WIDTH);
_y_scale_pc_label = new StaticText (this, _("%"));
_line_spacing_label = create_label (this, _("Line spacing"), true);
- _line_spacing = new SpinCtrl (this, spin_width);
+ _line_spacing = new SpinCtrl (this, DCPOMATIC_SPIN_CTRL_WIDTH);
_line_spacing_pc_label = new StaticText (this, _("%"));
_stream_label = create_label (this, _("Stream"), true);
_y_scale->SetRange (0, 1000);
_line_spacing->SetRange (0, 1000);
- _reference->Bind (wxEVT_CHECKBOX, boost::bind (&TextPanel::reference_clicked, this));
- _use->Bind (wxEVT_CHECKBOX, boost::bind (&TextPanel::use_toggled, this));
+ _reference->bind(&TextPanel::reference_clicked, this);
+ _use->bind(&TextPanel::use_toggled, this);
_type->Bind (wxEVT_CHOICE, boost::bind (&TextPanel::type_changed, this));
- _burn->Bind (wxEVT_CHECKBOX, boost::bind (&TextPanel::burn_toggled, this));
+ _burn->bind(&TextPanel::burn_toggled, this);
_x_offset->Bind (wxEVT_SPINCTRL, boost::bind (&TextPanel::x_offset_changed, this));
_y_offset->Bind (wxEVT_SPINCTRL, boost::bind (&TextPanel::y_offset_changed, this));
_x_scale->Bind (wxEVT_SPINCTRL, boost::bind (&TextPanel::x_scale_changed, this));
add_to_grid();
content_selection_changed ();
+
+ _sizer->Layout ();
}
case TextType::OPEN_SUBTITLE:
if (_dcp_track_label) {
_dcp_track_label->Destroy ();
- _dcp_track_label = 0;
+ _dcp_track_label = nullptr;
}
if (_dcp_track) {
_dcp_track->Destroy ();
}
if (!_outline_subtitles) {
_outline_subtitles = new CheckBox (this, _("Show subtitle area"));
- _outline_subtitles->Bind (wxEVT_CHECKBOX, boost::bind (&TextPanel::outline_subtitles_changed, this));
+ _outline_subtitles->bind(&TextPanel::outline_subtitles_changed, this);
_grid->Add (_outline_subtitles, wxGBPosition(_outline_subtitles_row, 0), wxGBSpan(1, 2));
}
-
+ if (!_language) {
+ _language_label = create_label (this, _("Language"), true);
+ add_label_to_sizer (_grid, _language_label, true, wxGBPosition(_ccap_track_or_language_row, 0));
+ _language_sizer = new wxBoxSizer (wxHORIZONTAL);
+ _language = new LanguageTagWidget (this, _("Language of these subtitles"), boost::none, wxString("en-US-"));
+ _language->Changed.connect (boost::bind(&TextPanel::language_changed, this));
+ _language_sizer->Add (_language->sizer(), 1, wxRIGHT, DCPOMATIC_SIZER_GAP);
+ _language_type = new wxChoice (this, wxID_ANY);
+ /// TRANSLATORS: Main and Additional here are a choice for whether a set of subtitles is in the "main" language of the
+ /// film or an "additional" language.
+ _language_type->Append (_("Main"));
+ _language_type->Append (_("Additional"));
+ _language_type->Bind (wxEVT_CHOICE, boost::bind(&TextPanel::language_is_additional_changed, this));
+ _language_sizer->Add (_language_type, 0, wxALIGN_CENTER_VERTICAL | wxTOP, DCPOMATIC_CHOICE_TOP_PAD);
+ _grid->Add (_language_sizer, wxGBPosition(_ccap_track_or_language_row, 1), wxGBSpan(1, 2));
+ film_content_changed (TextContentProperty::LANGUAGE);
+ film_content_changed (TextContentProperty::LANGUAGE_IS_ADDITIONAL);
+ }
break;
case TextType::CLOSED_CAPTION:
+ if (_language_label) {
+ _language_label->Destroy ();
+ _language_label = nullptr;
+ _grid->Remove (_language->sizer());
+ delete _language;
+ _grid->Remove (_language_sizer);
+ _language_sizer = nullptr;
+ _language = nullptr;
+ _language_type->Destroy ();
+ _language_type = nullptr;
+ }
if (!_dcp_track_label) {
_dcp_track_label = create_label (this, _("CCAP track"), true);
- add_label_to_sizer (_grid, _dcp_track_label, true, wxGBPosition(_ccap_track_row, 0));
+ add_label_to_sizer (_grid, _dcp_track_label, true, wxGBPosition(_ccap_track_or_language_row, 0));
}
if (!_dcp_track) {
_dcp_track = new wxChoice (this, wxID_ANY);
_dcp_track->Bind (wxEVT_CHOICE, boost::bind(&TextPanel::dcp_track_changed, this));
- _grid->Add (_dcp_track, wxGBPosition(_ccap_track_row, 1), wxDefaultSpan, wxEXPAND);
+ _grid->Add (_dcp_track, wxGBPosition(_ccap_track_or_language_row, 1), wxDefaultSpan, wxEXPAND);
update_dcp_tracks ();
film_content_changed (TextContentProperty::DCP_TRACK);
}
if (_outline_subtitles) {
_outline_subtitles->Destroy ();
- _outline_subtitles = 0;
+ _outline_subtitles = nullptr;
clear_outline_subtitles ();
}
break;
{
add_label_to_sizer (_grid, _line_spacing_label, true, wxGBPosition (r, 0));
- wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+ auto s = new wxBoxSizer (wxHORIZONTAL);
s->Add (_line_spacing);
add_label_to_sizer (s, _line_spacing_pc_label, false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
_grid->Add (s, wxGBPosition (r, 1));
++r;
}
- _ccap_track_row = r;
+ _ccap_track_or_language_row = r;
++r;
add_label_to_sizer (_grid, _stream_label, true, wxGBPosition (r, 0));
{
auto s = new wxBoxSizer (wxHORIZONTAL);
- s->Add (_text_view_button, 1, wxALL, DCPOMATIC_SIZER_GAP);
- s->Add (_fonts_dialog_button, 1, wxALL, DCPOMATIC_SIZER_GAP);
- s->Add (_appearance_dialog_button, 1, wxALL, DCPOMATIC_SIZER_GAP);
+ s->Add (_text_view_button, 0, wxALL, DCPOMATIC_SIZER_GAP);
+ s->Add (_fonts_dialog_button, 0, wxALL, DCPOMATIC_SIZER_GAP);
+ s->Add (_appearance_dialog_button, 0, wxALL, DCPOMATIC_SIZER_GAP);
- _grid->Add (s, wxGBPosition (r, 0), wxGBSpan (1, 2));
+ _grid->Add (s, wxGBPosition(r, 0), wxGBSpan(1, 2));
++r;
}
/* XXX: don't display the "magic" track which has empty name and language;
this is a nasty hack (see also Film::closed_caption_tracks)
*/
- if (!i.name.empty() || !i.language.empty()) {
+ if (!i.name.empty() || i.language) {
_dcp_track->Append (std_to_wx(i.summary()));
}
}
optional<DCPTextTrack> track;
if (_dcp_track->GetSelection() == int(_dcp_track->GetCount()) - 1) {
- auto d = new DCPTextTrackDialog (this);
+ auto d = make_wx<DCPTextTrackDialog>(this);
if (d->ShowModal() == wxID_OK) {
track = d->get();
}
- d->Destroy ();
} else {
/* Find the DCPTextTrack that was selected */
for (auto i: _parent->film()->closed_caption_tracks()) {
if (_dcp_track) {
update_dcp_track_selection ();
}
+ } else if (property == TextContentProperty::LANGUAGE) {
+ if (_language) {
+ _language->set (text ? text->language() : boost::none);
+ }
+ } else if (property == TextContentProperty::LANGUAGE_IS_ADDITIONAL) {
+ if (_language_type) {
+ _language_type->SetSelection (text ? (text->language_is_additional() ? 1 : 0) : 0);
+ }
} else if (property == DCPContentProperty::REFERENCE_TEXT) {
if (scs) {
auto dcp = dynamic_pointer_cast<DCPContent> (scs);
auto sel = _parent->selected_text ();
for (auto i: sel) {
/* These are the content types that could include subtitles */
- auto fc = std::dynamic_pointer_cast<const FFmpegContent> (i);
- auto sc = std::dynamic_pointer_cast<const StringTextFileContent> (i);
- auto dc = std::dynamic_pointer_cast<const DCPContent> (i);
- auto dsc = std::dynamic_pointer_cast<const DCPSubtitleContent> (i);
+ auto fc = std::dynamic_pointer_cast<const FFmpegContent>(i);
+ auto sc = std::dynamic_pointer_cast<const StringTextFileContent>(i);
+ auto dc = std::dynamic_pointer_cast<const DCPContent>(i);
+ auto dsc = std::dynamic_pointer_cast<const DCPSubtitleContent>(i);
if (fc) {
if (!fc->text.empty()) {
++ffmpeg_subs;
shared_ptr<DCPContent> dcp;
if (sel.size() == 1) {
- dcp = dynamic_pointer_cast<DCPContent> (sel.front ());
+ dcp = dynamic_pointer_cast<DCPContent>(sel.front());
}
string why_not;
bool const reference = _reference->GetValue ();
- TextType const type = current_type ();
+ auto const type = current_type ();
/* Set up _type */
_type->Clear ();
auto a = fcs->subtitle_streams ();
auto i = a.begin ();
- auto const s = string_client_data (_stream->GetClientObject (_stream->GetSelection ()));
+ auto const s = string_client_data (_stream->GetClientObject(_stream->GetSelection()));
while (i != a.end() && (*i)->identifier () != s) {
++i;
}
film_content_changed (TextContentProperty::FONTS);
film_content_changed (TextContentProperty::TYPE);
film_content_changed (TextContentProperty::DCP_TRACK);
+ film_content_changed (TextContentProperty::LANGUAGE);
+ film_content_changed (TextContentProperty::LANGUAGE_IS_ADDITIONAL);
film_content_changed (DCPContentProperty::REFERENCE_TEXT);
}
void
TextPanel::text_view_clicked ()
{
- if (_text_view) {
- _text_view->Destroy ();
- _text_view = 0;
- }
-
auto c = _parent->selected_text ();
DCPOMATIC_ASSERT (c.size() == 1);
auto decoder = decoder_factory (_parent->film(), c.front(), false, false, shared_ptr<Decoder>());
if (decoder) {
- _text_view = new TextView (this, _parent->film(), c.front(), c.front()->text_of_original_type(_original_type), decoder, _parent->film_viewer());
+ _text_view.reset(this, _parent->film(), c.front(), c.front()->text_of_original_type(_original_type), decoder, _parent->film_viewer());
_text_view->Show ();
}
}
void
TextPanel::fonts_dialog_clicked ()
{
- if (_fonts_dialog) {
- _fonts_dialog->Destroy ();
- _fonts_dialog = nullptr;
- }
-
auto c = _parent->selected_text ();
DCPOMATIC_ASSERT (c.size() == 1);
- _fonts_dialog = new FontsDialog (this, c.front(), c.front()->text_of_original_type(_original_type));
+ _fonts_dialog.reset(this, c.front(), c.front()->text_of_original_type(_original_type));
_fonts_dialog->Show ();
}
auto c = _parent->selected_text ();
DCPOMATIC_ASSERT (c.size() == 1);
- auto d = new SubtitleAppearanceDialog (this, _parent->film(), c.front(), c.front()->text_of_original_type(_original_type));
- if (d->ShowModal () == wxID_OK) {
- d->apply ();
+ SubtitleAppearanceDialog dialog(this, _parent->film(), c.front(), c.front()->text_of_original_type(_original_type));
+ if (dialog.ShowModal() == wxID_OK) {
+ dialog.apply();
}
- d->Destroy ();
}
-
/** The user has clicked on the outline subtitles check box */
void
TextPanel::outline_subtitles_changed ()
}
_loading_analysis = true;
+ ScopeGuard sg = [this]() {
+ _loading_analysis = false;
+ setup_sensitivity();
+ };
+
setup_sensitivity ();
_analysis.reset ();
auto content = _analysis_content.lock ();
if (!content) {
- _loading_analysis = false;
- setup_sensitivity ();
return;
}
if (!boost::filesystem::exists(path)) {
for (auto i: JobManager::instance()->get()) {
- if (dynamic_pointer_cast<AnalyseSubtitlesJob>(i)) {
+ if (dynamic_pointer_cast<AnalyseSubtitlesJob>(i) && !i->finished()) {
i->cancel ();
}
}
_parent->film(), content, _analysis_finished_connection, bind(&TextPanel::analysis_finished, this)
);
return;
- }
+ }
update_outline_subtitles_in_viewer ();
- _loading_analysis = false;
- setup_sensitivity ();
}
void
TextPanel::update_outline_subtitles_in_viewer ()
{
- auto fv = _parent->film_viewer().lock();
- if (!fv) {
- return;
- }
+ auto& fv = _parent->film_viewer();
if (_analysis) {
auto rect = _analysis->bounding_box ();
if (rect) {
auto content = _analysis_content.lock ();
DCPOMATIC_ASSERT (content);
- rect->x += content->text.front()->x_offset();
- rect->y += content->text.front()->y_offset();
+ rect->x += content->text.front()->x_offset() - _analysis->analysis_x_offset();
+ rect->y += content->text.front()->y_offset() - _analysis->analysis_y_offset();
}
- fv->set_outline_subtitles (rect);
+ fv.set_outline_subtitles(rect);
} else {
- fv->set_outline_subtitles (optional<dcpomatic::Rect<double> >());
+ fv.set_outline_subtitles({});
}
}
void
TextPanel::analysis_finished ()
{
+ _loading_analysis = false;
+
auto content = _analysis_content.lock ();
if (!content) {
- _loading_analysis = false;
setup_sensitivity ();
return;
}
*/
error_dialog (_parent->window(), _("Could not analyse subtitles."));
clear_outline_subtitles ();
- _loading_analysis = false;
setup_sensitivity ();
return;
}
- _loading_analysis = false;
try_to_load_analysis ();
}
+
+void
+TextPanel::language_changed ()
+{
+ for (auto i: _parent->selected_text()) {
+ auto t = i->text_of_original_type(_original_type);
+ if (t) {
+ t->set_language (_language->get());
+ }
+ }
+}
+
+
+void
+TextPanel::language_is_additional_changed ()
+{
+ for (auto i: _parent->selected_text()) {
+ auto t = i->text_of_original_type(_original_type);
+ if (t) {
+ t->set_language_is_additional (_language_type->GetSelection() == 1);
+ }
+ }
+}
+