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