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::set_video_frame_rate ()
203 if (_video_frame_rate->GetValue() != wxT("")) {
204 _content->set_video_frame_rate (locale_convert<double>(wx_to_std(_video_frame_rate->GetValue())));
206 _content->unset_video_frame_rate ();
209 _set_video_frame_rate->Enable (false);
214 ContentAdvancedDialog::video_frame_rate_changed ()
217 /* If the user clicks "set" now, with no frame rate entered, it would unset the video
218 frame rate in the selected content. This can't be allowed for some content types.
220 if (_video_frame_rate->GetValue() == wxT("") && (dynamic_pointer_cast<DCPContent>(_content) || dynamic_pointer_cast<FFmpegContent>(_content))) {
224 _set_video_frame_rate->Enable (enable);
229 ContentAdvancedDialog::setup_sensitivity ()
231 _burnt_subtitle->Enable (static_cast<bool>(_content->video));
232 _burnt_subtitle_language->enable (_content->video && _burnt_subtitle->GetValue());
237 ContentAdvancedDialog::burnt_subtitle_changed ()
239 setup_sensitivity ();
244 ContentAdvancedDialog::burnt_subtitle_language_changed ()
246 DCPOMATIC_ASSERT (_content->video);
247 _content->video->set_burnt_subtitle_language (_burnt_subtitle_language->get());