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/video_content.h"
34 #include <wx/gbsizer.h>
35 DCPOMATIC_DISABLE_WARNINGS
37 #include <wx/propgrid/property.h>
38 #include <wx/propgrid/props.h>
39 DCPOMATIC_ENABLE_WARNINGS
40 #include <boost/bind/bind.hpp>
46 using std::dynamic_pointer_cast;
47 using boost::optional;
48 using std::shared_ptr;
49 #if BOOST_VERSION >= 106100
50 using namespace boost::placeholders;
52 using dcp::locale_convert;
56 ContentAdvancedDialog::ContentAdvancedDialog (wxWindow* parent, shared_ptr<Content> content)
57 : wxDialog (parent, wxID_ANY, _("Advanced content settings"))
60 auto sizer = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
65 auto size = dc.GetTextExtent (wxT ("A quite long name"));
67 size.SetWidth (size.GetWidth() + 64);
71 add_label_to_sizer (sizer, this, _("Video filters"), true, wxGBPosition(r, 0));
72 _filters = new StaticText (this, _("None"), wxDefaultPosition, size);
73 _filters_button = new Button (this, _("Edit..."));
74 auto filters = new wxBoxSizer (wxHORIZONTAL);
75 filters->Add (_filters, 1, wxALL | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_GAP);
76 filters->Add (_filters_button, 0, wxALL, DCPOMATIC_SIZER_GAP);
77 sizer->Add (filters, wxGBPosition(r, 1), wxGBSpan(1, 2));
80 wxStaticText* video_frame_rate_label;
81 if (_content->video) {
82 video_frame_rate_label = add_label_to_sizer (sizer, this, _("Override detected video frame rate"), true, wxGBPosition(r, 0));
84 video_frame_rate_label = add_label_to_sizer (sizer, this, _("Video frame rate that content was prepared for"), true, wxGBPosition(r, 0));
86 _video_frame_rate = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0, wxNumericPropertyValidator(wxNumericPropertyValidator::Float));
87 sizer->Add (_video_frame_rate, wxGBPosition(r, 1));
88 _set_video_frame_rate = new Button (this, _("Set"));
89 _set_video_frame_rate->Enable (false);
90 sizer->Add (_set_video_frame_rate, wxGBPosition(r, 2));
93 /// TRANSLATORS: next to this control is a language selector, so together they will read, for example
94 /// "Video has burnt-in subtitles in the language fr-FR"
95 _burnt_subtitle = new wxCheckBox (this, wxID_ANY, _("Video has burnt-in subtitles in the language"));
96 sizer->Add (_burnt_subtitle, wxGBPosition(r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
97 _burnt_subtitle_language = new LanguageTagWidget (this, _("Language of burnt-in subtitles in this content"), content->video ? content->video->burnt_subtitle_language() : boost::none);
98 sizer->Add (_burnt_subtitle_language->sizer(), wxGBPosition(r, 1), wxGBSpan(1, 2), wxEXPAND);
101 auto ignore_video = new wxCheckBox (this, wxID_ANY, _("Ignore this content's video and use only audio, subtitles and closed captions"));
102 sizer->Add (ignore_video, wxGBPosition(r, 0), wxGBSpan(1, 3));
105 auto overall = new wxBoxSizer (wxVERTICAL);
106 overall->Add (sizer, 1, wxALL, DCPOMATIC_DIALOG_BORDER);
107 auto buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
109 overall->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
112 SetSizerAndFit (overall);
114 ignore_video->Enable (static_cast<bool>(_content->video));
115 ignore_video->SetValue (_content->video ? !content->video->use() : false);
118 bool const single_frame_image_content = dynamic_pointer_cast<const ImageContent>(_content) && _content->number_of_paths() == 1;
119 video_frame_rate_label->Enable (!single_frame_image_content);
120 _video_frame_rate->Enable (!single_frame_image_content);
122 auto vfr = _content->video_frame_rate ();
124 _video_frame_rate->SetValue (std_to_wx(locale_convert<string>(*vfr)));
127 _burnt_subtitle->SetValue (_content->video && static_cast<bool>(_content->video->burnt_subtitle_language()));
128 _burnt_subtitle_language->set (_content->video ? _content->video->burnt_subtitle_language() : boost::none);
130 ignore_video->Bind (wxEVT_CHECKBOX, bind(&ContentAdvancedDialog::ignore_video_changed, this, _1));
131 _filters_button->Bind (wxEVT_BUTTON, bind(&ContentAdvancedDialog::edit_filters, this));
132 _set_video_frame_rate->Bind (wxEVT_BUTTON, bind(&ContentAdvancedDialog::set_video_frame_rate, this));
133 _video_frame_rate->Bind (wxEVT_TEXT, boost::bind(&ContentAdvancedDialog::video_frame_rate_changed, this));
134 _burnt_subtitle->Bind (wxEVT_CHECKBOX, boost::bind(&ContentAdvancedDialog::burnt_subtitle_changed, this));
135 _burnt_subtitle_language->Changed.connect (boost::bind(&ContentAdvancedDialog::burnt_subtitle_language_changed, this));
137 setup_sensitivity ();
142 ContentAdvancedDialog::ignore_video_changed (wxCommandEvent& ev)
144 if (_content->video) {
145 _content->video->set_use (!ev.IsChecked());
151 ContentAdvancedDialog::setup_filters ()
153 auto fcs = dynamic_pointer_cast<FFmpegContent>(_content);
155 checked_set (_filters, _("None"));
156 _filters->Enable (false);
157 _filters_button->Enable (false);
161 auto p = Filter::ffmpeg_string (fcs->filters());
163 checked_set (_filters, _("None"));
165 if (p.length() > 25) {
166 p = p.substr(0, 25) + "...";
168 checked_set (_filters, p);
174 ContentAdvancedDialog::edit_filters ()
176 auto fcs = dynamic_pointer_cast<FFmpegContent>(_content);
181 auto d = new FilterDialog (this, fcs->filters());
182 d->ActiveChanged.connect (bind(&ContentAdvancedDialog::filters_changed, this, _1));
189 ContentAdvancedDialog::filters_changed (vector<Filter const *> filters)
191 auto fcs = dynamic_pointer_cast<FFmpegContent>(_content);
196 fcs->set_filters (filters);
202 ContentAdvancedDialog::set_video_frame_rate ()
204 if (_video_frame_rate->GetValue() != wxT("")) {
205 _content->set_video_frame_rate (locale_convert<double>(wx_to_std(_video_frame_rate->GetValue())));
207 _content->unset_video_frame_rate ();
210 _set_video_frame_rate->Enable (false);
215 ContentAdvancedDialog::video_frame_rate_changed ()
218 /* If the user clicks "set" now, with no frame rate entered, it would unset the video
219 frame rate in the selected content. This can't be allowed for some content types.
221 if (_video_frame_rate->GetValue() == wxT("") && (dynamic_pointer_cast<DCPContent>(_content) || dynamic_pointer_cast<FFmpegContent>(_content))) {
225 _set_video_frame_rate->Enable (enable);
230 ContentAdvancedDialog::setup_sensitivity ()
232 _burnt_subtitle->Enable (static_cast<bool>(_content->video));
233 _burnt_subtitle_language->enable (_content->video && _burnt_subtitle->GetValue());
238 ContentAdvancedDialog::burnt_subtitle_changed ()
240 setup_sensitivity ();
245 ContentAdvancedDialog::burnt_subtitle_language_changed ()
247 DCPOMATIC_ASSERT (_content->video);
248 _content->video->set_burnt_subtitle_language (_burnt_subtitle_language->get());