Work around strange build error on Ubuntu 18.04
[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::string;
45 using std::vector;
46 using boost::bind;
47 using std::dynamic_pointer_cast;
48 using boost::optional;
49 using std::shared_ptr;
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         auto 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         ignore_video->Bind (wxEVT_CHECKBOX, bind(&ContentAdvancedDialog::ignore_video_changed, this, _1));
132         _filters_button->Bind (wxEVT_BUTTON, bind(&ContentAdvancedDialog::edit_filters, this));
133         _set_video_frame_rate->Bind (wxEVT_BUTTON, bind(&ContentAdvancedDialog::set_video_frame_rate, this));
134         _video_frame_rate->Bind (wxEVT_TEXT, boost::bind(&ContentAdvancedDialog::video_frame_rate_changed, this));
135         _burnt_subtitle->Bind (wxEVT_CHECKBOX, boost::bind(&ContentAdvancedDialog::burnt_subtitle_changed, this));
136         _burnt_subtitle_language->Changed.connect (boost::bind(&ContentAdvancedDialog::burnt_subtitle_language_changed, this));
137
138         setup_sensitivity ();
139 }
140
141
142 void
143 ContentAdvancedDialog::ignore_video_changed (wxCommandEvent& ev)
144 {
145          if (_content->video) {
146                  _content->video->set_use (!ev.IsChecked());
147          }
148 }
149
150
151 void
152 ContentAdvancedDialog::setup_filters ()
153 {
154         auto fcs = dynamic_pointer_cast<FFmpegContent>(_content);
155         if (!fcs) {
156                 checked_set (_filters, _("None"));
157                 _filters->Enable (false);
158                 _filters_button->Enable (false);
159                 return;
160         }
161
162         auto p = Filter::ffmpeg_string (fcs->filters());
163         if (p.empty()) {
164                 checked_set (_filters, _("None"));
165         } else {
166                 if (p.length() > 25) {
167                         p = p.substr(0, 25) + "...";
168                 }
169                 checked_set (_filters, p);
170         }
171 }
172
173
174 void
175 ContentAdvancedDialog::edit_filters ()
176 {
177         auto fcs = dynamic_pointer_cast<FFmpegContent>(_content);
178         if (!fcs) {
179                 return;
180         }
181
182         auto d = new FilterDialog (this, fcs->filters());
183         d->ActiveChanged.connect (bind(&ContentAdvancedDialog::filters_changed, this, _1));
184         d->ShowModal ();
185         d->Destroy ();
186 }
187
188
189 void
190 ContentAdvancedDialog::filters_changed (vector<Filter const *> filters)
191 {
192         auto fcs = dynamic_pointer_cast<FFmpegContent>(_content);
193         if (!fcs) {
194                 return;
195         }
196
197         fcs->set_filters (filters);
198         setup_filters ();
199 }
200
201
202 void
203 ContentAdvancedDialog::set_video_frame_rate ()
204 {
205         if (_video_frame_rate->GetValue() != wxT("")) {
206                 _content->set_video_frame_rate (locale_convert<double>(wx_to_std(_video_frame_rate->GetValue())));
207         } else {
208                 _content->unset_video_frame_rate ();
209         }
210
211         _set_video_frame_rate->Enable (false);
212 }
213
214
215 void
216 ContentAdvancedDialog::video_frame_rate_changed ()
217 {
218        bool enable = true;
219        /* If the user clicks "set" now, with no frame rate entered, it would unset the video
220           frame rate in the selected content.  This can't be allowed for some content types.
221        */
222        if (_video_frame_rate->GetValue() == wxT("") && (dynamic_pointer_cast<DCPContent>(_content) || dynamic_pointer_cast<FFmpegContent>(_content))) {
223                enable = false;
224        }
225
226        _set_video_frame_rate->Enable (enable);
227 }
228
229
230 void
231 ContentAdvancedDialog::setup_sensitivity ()
232 {
233         _burnt_subtitle->Enable (static_cast<bool>(_content->video));
234         _burnt_subtitle_language->enable (_content->video && _burnt_subtitle->GetValue());
235 }
236
237
238 void
239 ContentAdvancedDialog::burnt_subtitle_changed ()
240 {
241         setup_sensitivity ();
242 }
243
244
245 void
246 ContentAdvancedDialog::burnt_subtitle_language_changed ()
247 {
248         DCPOMATIC_ASSERT (_content->video);
249         _content->video->set_burnt_subtitle_language (_burnt_subtitle_language->get());
250 }
251