Supporters update.
[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_util.h"
29 #include "lib/content.h"
30 #include "lib/dcp_content.h"
31 #include "lib/filter.h"
32 #include "lib/ffmpeg_content.h"
33 #include "lib/image_content.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>
40 #include <wx/wx.h>
41 LIBDCP_ENABLE_WARNINGS
42 #include <boost/bind/bind.hpp>
43
44
45 using std::dynamic_pointer_cast;
46 using std::shared_ptr;
47 using std::string;
48 using std::vector;
49 using boost::bind;
50 using boost::optional;
51 #if BOOST_VERSION >= 106100
52 using namespace boost::placeholders;
53 #endif
54 using dcp::locale_convert;
55
56
57
58 ContentAdvancedDialog::ContentAdvancedDialog (wxWindow* parent, shared_ptr<Content> content)
59         : wxDialog (parent, wxID_ANY, _("Advanced content settings"))
60         , _content (content)
61 {
62         auto sizer = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
63
64         int r = 0;
65
66         wxClientDC dc (this);
67         auto size = dc.GetTextExtent (wxT ("A quite long name"));
68 #ifdef __WXGTK3__
69         size.SetWidth (size.GetWidth() + 64);
70 #endif
71         size.SetHeight (-1);
72
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));
80         ++r;
81
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));
85         } else {
86                 video_frame_rate_label = add_label_to_sizer (sizer, this, _("Video frame rate that content was prepared for"), true, wxGBPosition(r, 0));
87         }
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));
93         ++r;
94
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 CheckBox(this, _("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);
101         ++r;
102
103         _ignore_video = new CheckBox(this, _("Ignore this content's video and use only audio, subtitles and closed captions"));
104         sizer->Add(_ignore_video, wxGBPosition(r, 0), wxGBSpan(1, 3));
105         ++r;
106
107         auto overall = new wxBoxSizer (wxVERTICAL);
108         overall->Add (sizer, 1, wxALL, DCPOMATIC_DIALOG_BORDER);
109         auto buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
110         if (buttons) {
111                 overall->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
112         }
113
114         SetSizerAndFit (overall);
115
116         _ignore_video->Enable(static_cast<bool>(_content->video));
117         _ignore_video->SetValue(_content->video ? !content->video->use() : false);
118
119         auto fcs = dynamic_pointer_cast<FFmpegContent>(content);
120         _filters_allowed = static_cast<bool>(fcs);
121         if (fcs) {
122                 _filters_list = fcs->filters();
123         }
124         setup_filters ();
125
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);
129
130         auto vfr = _content->video_frame_rate ();
131         if (vfr) {
132                 _video_frame_rate->SetValue (std_to_wx(locale_convert<string>(*vfr)));
133         }
134
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);
137
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(&ContentAdvancedDialog::burnt_subtitle_changed, this);
142
143         setup_sensitivity ();
144 }
145
146
147 bool
148 ContentAdvancedDialog::ignore_video() const
149 {
150         return _ignore_video->GetValue();
151 }
152
153
154 void
155 ContentAdvancedDialog::setup_filters ()
156 {
157         if (!_filters_allowed) {
158                 checked_set (_filters, _("None"));
159                 _filters->Enable (false);
160                 _filters_button->Enable (false);
161                 return;
162         }
163
164         auto p = Filter::ffmpeg_string(_filters_list);
165         if (p.empty()) {
166                 checked_set (_filters, _("None"));
167         } else {
168                 if (p.length() > 25) {
169                         p = p.substr(0, 25) + "...";
170                 }
171                 checked_set (_filters, p);
172         }
173 }
174
175
176 void
177 ContentAdvancedDialog::edit_filters ()
178 {
179         if (!_filters_allowed) {
180                 return;
181         }
182
183         auto dialog = make_wx<FilterDialog>(this, _filters_list);
184         dialog->ActiveChanged.connect(bind(&ContentAdvancedDialog::filters_changed, this, _1));
185         dialog->ShowModal();
186 }
187
188
189 void
190 ContentAdvancedDialog::filters_changed(vector<Filter> const& filters)
191 {
192         _filters_list = filters;
193         setup_filters ();
194 }
195
196
197 optional<double>
198 ContentAdvancedDialog::video_frame_rate() const
199 {
200         if (_video_frame_rate->GetValue() == wxT("")) {
201                 return {};
202         }
203
204         return locale_convert<double>(wx_to_std(_video_frame_rate->GetValue()));
205 }
206
207
208 void
209 ContentAdvancedDialog::set_video_frame_rate ()
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 optional<dcp::LanguageTag>
246 ContentAdvancedDialog::burnt_subtitle_language() const
247 {
248         return _burnt_subtitle_language->get();
249 }
250