2 Copyright (C) 2020-2021 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
6 DCP-o-matic is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 DCP-o-matic is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
22 #include "content_advanced_dialog.h"
23 #include "dcpomatic_button.h"
24 #include "filter_dialog.h"
25 #include "language_tag_widget.h"
26 #include "static_text.h"
28 #include "lib/content.h"
29 #include "lib/dcp_content.h"
30 #include "lib/filter.h"
31 #include "lib/ffmpeg_content.h"
32 #include "lib/image_content.h"
33 #include "lib/scope_guard.h"
34 #include "lib/video_content.h"
35 #include <dcp/warnings.h>
36 LIBDCP_DISABLE_WARNINGS
37 #include <wx/gbsizer.h>
38 #include <wx/propgrid/property.h>
39 #include <wx/propgrid/props.h>
41 LIBDCP_ENABLE_WARNINGS
42 #include <boost/bind/bind.hpp>
45 using std::dynamic_pointer_cast;
46 using std::shared_ptr;
50 using boost::optional;
51 #if BOOST_VERSION >= 106100
52 using namespace boost::placeholders;
54 using dcp::locale_convert;
58 ContentAdvancedDialog::ContentAdvancedDialog (wxWindow* parent, shared_ptr<Content> content)
59 : wxDialog (parent, wxID_ANY, _("Advanced content settings"))
62 auto sizer = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
67 auto size = dc.GetTextExtent (wxT ("A quite long name"));
69 size.SetWidth (size.GetWidth() + 64);
73 add_label_to_sizer (sizer, this, _("Video filters"), true, wxGBPosition(r, 0));
74 _filters = new StaticText (this, _("None"), wxDefaultPosition, size);
75 _filters_button = new Button (this, _("Edit..."));
76 auto filters = new wxBoxSizer (wxHORIZONTAL);
77 filters->Add (_filters, 1, wxALL | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_GAP);
78 filters->Add (_filters_button, 0, wxALL, DCPOMATIC_SIZER_GAP);
79 sizer->Add (filters, wxGBPosition(r, 1), wxGBSpan(1, 2));
82 wxStaticText* video_frame_rate_label;
83 if (_content->video) {
84 video_frame_rate_label = add_label_to_sizer (sizer, this, _("Override detected video frame rate"), true, wxGBPosition(r, 0));
86 video_frame_rate_label = add_label_to_sizer (sizer, this, _("Video frame rate that content was prepared for"), true, wxGBPosition(r, 0));
88 _video_frame_rate = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0, wxNumericPropertyValidator(wxNumericPropertyValidator::Float));
89 sizer->Add (_video_frame_rate, wxGBPosition(r, 1));
90 _set_video_frame_rate = new Button (this, _("Set"));
91 _set_video_frame_rate->Enable (false);
92 sizer->Add (_set_video_frame_rate, wxGBPosition(r, 2));
95 /// TRANSLATORS: next to this control is a language selector, so together they will read, for example
96 /// "Video has burnt-in subtitles in the language fr-FR"
97 _burnt_subtitle = new wxCheckBox (this, wxID_ANY, _("Video has burnt-in subtitles in the language"));
98 sizer->Add (_burnt_subtitle, wxGBPosition(r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
99 _burnt_subtitle_language = new LanguageTagWidget (this, _("Language of burnt-in subtitles in this content"), content->video ? content->video->burnt_subtitle_language() : boost::none);
100 sizer->Add (_burnt_subtitle_language->sizer(), wxGBPosition(r, 1), wxGBSpan(1, 2), wxEXPAND);
103 _ignore_video = new wxCheckBox (this, wxID_ANY, _("Ignore this content's video and use only audio, subtitles and closed captions"));
104 sizer->Add(_ignore_video, wxGBPosition(r, 0), wxGBSpan(1, 3));
107 auto overall = new wxBoxSizer (wxVERTICAL);
108 overall->Add (sizer, 1, wxALL, DCPOMATIC_DIALOG_BORDER);
109 auto buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
111 overall->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
114 SetSizerAndFit (overall);
116 _ignore_video->Enable(static_cast<bool>(_content->video));
117 _ignore_video->SetValue(_content->video ? !content->video->use() : false);
119 auto fcs = dynamic_pointer_cast<FFmpegContent>(content);
120 _filters_allowed = static_cast<bool>(fcs);
122 _filters_list = fcs->filters();
126 bool const single_frame_image_content = dynamic_pointer_cast<const ImageContent>(_content) && _content->number_of_paths() == 1;
127 video_frame_rate_label->Enable (!single_frame_image_content);
128 _video_frame_rate->Enable (!single_frame_image_content);
130 auto vfr = _content->video_frame_rate ();
132 _video_frame_rate->SetValue (std_to_wx(locale_convert<string>(*vfr)));
135 _burnt_subtitle->SetValue (_content->video && static_cast<bool>(_content->video->burnt_subtitle_language()));
136 _burnt_subtitle_language->set (_content->video ? _content->video->burnt_subtitle_language() : boost::none);
138 _filters_button->Bind (wxEVT_BUTTON, bind(&ContentAdvancedDialog::edit_filters, this));
139 _set_video_frame_rate->Bind (wxEVT_BUTTON, bind(&ContentAdvancedDialog::set_video_frame_rate, this));
140 _video_frame_rate->Bind (wxEVT_TEXT, boost::bind(&ContentAdvancedDialog::video_frame_rate_changed, this));
141 _burnt_subtitle->Bind (wxEVT_CHECKBOX, boost::bind(&ContentAdvancedDialog::burnt_subtitle_changed, this));
142 _burnt_subtitle_language->Changed.connect (boost::bind(&ContentAdvancedDialog::burnt_subtitle_language_changed, this));
144 setup_sensitivity ();
149 ContentAdvancedDialog::ignore_video() const
151 return _ignore_video->GetValue();
156 ContentAdvancedDialog::setup_filters ()
158 if (!_filters_allowed) {
159 checked_set (_filters, _("None"));
160 _filters->Enable (false);
161 _filters_button->Enable (false);
165 auto p = Filter::ffmpeg_string(_filters_list);
167 checked_set (_filters, _("None"));
169 if (p.length() > 25) {
170 p = p.substr(0, 25) + "...";
172 checked_set (_filters, p);
178 ContentAdvancedDialog::edit_filters ()
180 if (!_filters_allowed) {
184 auto dialog = new FilterDialog(this, _filters_list);
185 ScopeGuard sg = [dialog]() { dialog->Destroy(); };
187 dialog->ActiveChanged.connect(bind(&ContentAdvancedDialog::filters_changed, this, _1));
193 ContentAdvancedDialog::filters_changed (vector<Filter const *> filters)
195 _filters_list = filters;
201 ContentAdvancedDialog::video_frame_rate() const
203 if (_video_frame_rate->GetValue() == wxT("")) {
207 return locale_convert<double>(wx_to_std(_video_frame_rate->GetValue()));
212 ContentAdvancedDialog::set_video_frame_rate ()
214 _set_video_frame_rate->Enable (false);
219 ContentAdvancedDialog::video_frame_rate_changed ()
222 /* If the user clicks "set" now, with no frame rate entered, it would unset the video
223 frame rate in the selected content. This can't be allowed for some content types.
225 if (_video_frame_rate->GetValue() == wxT("") && (dynamic_pointer_cast<DCPContent>(_content) || dynamic_pointer_cast<FFmpegContent>(_content))) {
229 _set_video_frame_rate->Enable (enable);
234 ContentAdvancedDialog::setup_sensitivity ()
236 _burnt_subtitle->Enable (static_cast<bool>(_content->video));
237 _burnt_subtitle_language->enable (_content->video && _burnt_subtitle->GetValue());
242 ContentAdvancedDialog::burnt_subtitle_changed ()
244 setup_sensitivity ();
249 ContentAdvancedDialog::burnt_subtitle_language_changed ()
251 DCPOMATIC_ASSERT (_content->video);
252 _content->video->set_burnt_subtitle_language (_burnt_subtitle_language->get());