1a2a8b6a36a83a3e3b001622c5e451985ada8ac1
[dcpomatic.git] / src / wx / content_advanced_dialog.cc
1 /*
2     Copyright (C) 2020-2021 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
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.
10
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.
15
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/>.
18
19 */
20
21
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"
27 #include "wx_util.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 <dcp/warnings.h>
35 LIBDCP_DISABLE_WARNINGS
36 #include <wx/gbsizer.h>
37 #include <wx/propgrid/property.h>
38 #include <wx/propgrid/props.h>
39 #include <wx/wx.h>
40 LIBDCP_ENABLE_WARNINGS
41 #include <boost/bind/bind.hpp>
42
43
44 using std::dynamic_pointer_cast;
45 using std::shared_ptr;
46 using std::string;
47 using std::vector;
48 using boost::bind;
49 using boost::optional;
50 #if BOOST_VERSION >= 106100
51 using namespace boost::placeholders;
52 #endif
53 using dcp::locale_convert;
54
55
56
57 ContentAdvancedDialog::ContentAdvancedDialog (wxWindow* parent, shared_ptr<Content> content)
58         : wxDialog (parent, wxID_ANY, _("Advanced content settings"))
59         , _content (content)
60 {
61         auto sizer = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
62
63         int r = 0;
64
65         wxClientDC dc (this);
66         auto size = dc.GetTextExtent (wxT ("A quite long name"));
67 #ifdef __WXGTK3__
68         size.SetWidth (size.GetWidth() + 64);
69 #endif
70         size.SetHeight (-1);
71
72         add_label_to_sizer (sizer, this, _("Video filters"), true, wxGBPosition(r, 0));
73         _filters = new StaticText (this, _("None"), wxDefaultPosition, size);
74         _filters_button = new Button (this, _("Edit..."));
75         auto filters = new wxBoxSizer (wxHORIZONTAL);
76         filters->Add (_filters, 1, wxALL | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_GAP);
77         filters->Add (_filters_button, 0, wxALL, DCPOMATIC_SIZER_GAP);
78         sizer->Add (filters, wxGBPosition(r, 1), wxGBSpan(1, 2));
79         ++r;
80
81         wxStaticText* video_frame_rate_label;
82         if (_content->video) {
83                 video_frame_rate_label = add_label_to_sizer (sizer, this, _("Override detected video frame rate"), true, wxGBPosition(r, 0));
84         } else {
85                 video_frame_rate_label = add_label_to_sizer (sizer, this, _("Video frame rate that content was prepared for"), true, wxGBPosition(r, 0));
86         }
87         _video_frame_rate = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0, wxNumericPropertyValidator(wxNumericPropertyValidator::Float));
88         sizer->Add (_video_frame_rate, wxGBPosition(r, 1));
89         _set_video_frame_rate = new Button (this, _("Set"));
90         _set_video_frame_rate->Enable (false);
91         sizer->Add (_set_video_frame_rate, wxGBPosition(r, 2));
92         ++r;
93
94         /// TRANSLATORS: next to this control is a language selector, so together they will read, for example
95         /// "Video has burnt-in subtitles in the language fr-FR"
96         _burnt_subtitle = new wxCheckBox (this, wxID_ANY, _("Video has burnt-in subtitles in the language"));
97         sizer->Add (_burnt_subtitle, wxGBPosition(r, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
98         _burnt_subtitle_language = new LanguageTagWidget (this, _("Language of burnt-in subtitles in this content"), content->video ? content->video->burnt_subtitle_language() : boost::none);
99         sizer->Add (_burnt_subtitle_language->sizer(), wxGBPosition(r, 1), wxGBSpan(1, 2), wxEXPAND);
100         ++r;
101
102         _ignore_video = new wxCheckBox (this, wxID_ANY, _("Ignore this content's video and use only audio, subtitles and closed captions"));
103         sizer->Add(_ignore_video, wxGBPosition(r, 0), wxGBSpan(1, 3));
104         ++r;
105
106         auto overall = new wxBoxSizer (wxVERTICAL);
107         overall->Add (sizer, 1, wxALL, DCPOMATIC_DIALOG_BORDER);
108         auto buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
109         if (buttons) {
110                 overall->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
111         }
112
113         SetSizerAndFit (overall);
114
115         _ignore_video->Enable(static_cast<bool>(_content->video));
116         _ignore_video->SetValue(_content->video ? !content->video->use() : false);
117         setup_filters ();
118
119         bool const single_frame_image_content = dynamic_pointer_cast<const ImageContent>(_content) && _content->number_of_paths() == 1;
120         video_frame_rate_label->Enable (!single_frame_image_content);
121         _video_frame_rate->Enable (!single_frame_image_content);
122
123         auto vfr = _content->video_frame_rate ();
124         if (vfr) {
125                 _video_frame_rate->SetValue (std_to_wx(locale_convert<string>(*vfr)));
126         }
127
128         _burnt_subtitle->SetValue (_content->video && static_cast<bool>(_content->video->burnt_subtitle_language()));
129         _burnt_subtitle_language->set (_content->video ? _content->video->burnt_subtitle_language() : boost::none);
130
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));
136
137         setup_sensitivity ();
138 }
139
140
141 bool
142 ContentAdvancedDialog::ignore_video() const
143 {
144         return _ignore_video->GetValue();
145 }
146
147
148 void
149 ContentAdvancedDialog::setup_filters ()
150 {
151         auto fcs = dynamic_pointer_cast<FFmpegContent>(_content);
152         if (!fcs) {
153                 checked_set (_filters, _("None"));
154                 _filters->Enable (false);
155                 _filters_button->Enable (false);
156                 return;
157         }
158
159         auto p = Filter::ffmpeg_string (fcs->filters());
160         if (p.empty()) {
161                 checked_set (_filters, _("None"));
162         } else {
163                 if (p.length() > 25) {
164                         p = p.substr(0, 25) + "...";
165                 }
166                 checked_set (_filters, p);
167         }
168 }
169
170
171 void
172 ContentAdvancedDialog::edit_filters ()
173 {
174         auto fcs = dynamic_pointer_cast<FFmpegContent>(_content);
175         if (!fcs) {
176                 return;
177         }
178
179         auto d = new FilterDialog (this, fcs->filters());
180         d->ActiveChanged.connect (bind(&ContentAdvancedDialog::filters_changed, this, _1));
181         d->ShowModal ();
182         d->Destroy ();
183 }
184
185
186 void
187 ContentAdvancedDialog::filters_changed (vector<Filter const *> filters)
188 {
189         auto fcs = dynamic_pointer_cast<FFmpegContent>(_content);
190         if (!fcs) {
191                 return;
192         }
193
194         fcs->set_filters (filters);
195         setup_filters ();
196 }
197
198
199 void
200 ContentAdvancedDialog::set_video_frame_rate ()
201 {
202         if (_video_frame_rate->GetValue() != wxT("")) {
203                 _content->set_video_frame_rate (locale_convert<double>(wx_to_std(_video_frame_rate->GetValue())));
204         } else {
205                 _content->unset_video_frame_rate ();
206         }
207
208         _set_video_frame_rate->Enable (false);
209 }
210
211
212 void
213 ContentAdvancedDialog::video_frame_rate_changed ()
214 {
215        bool enable = true;
216        /* If the user clicks "set" now, with no frame rate entered, it would unset the video
217           frame rate in the selected content.  This can't be allowed for some content types.
218        */
219        if (_video_frame_rate->GetValue() == wxT("") && (dynamic_pointer_cast<DCPContent>(_content) || dynamic_pointer_cast<FFmpegContent>(_content))) {
220                enable = false;
221        }
222
223        _set_video_frame_rate->Enable (enable);
224 }
225
226
227 void
228 ContentAdvancedDialog::setup_sensitivity ()
229 {
230         _burnt_subtitle->Enable (static_cast<bool>(_content->video));
231         _burnt_subtitle_language->enable (_content->video && _burnt_subtitle->GetValue());
232 }
233
234
235 void
236 ContentAdvancedDialog::burnt_subtitle_changed ()
237 {
238         setup_sensitivity ();
239 }
240
241
242 void
243 ContentAdvancedDialog::burnt_subtitle_language_changed ()
244 {
245         DCPOMATIC_ASSERT (_content->video);
246         _content->video->set_burnt_subtitle_language (_burnt_subtitle_language->get());
247 }
248