C++11 tidying.
[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 <wx/gbsizer.h>
35 DCPOMATIC_DISABLE_WARNINGS
36 #include <wx/wx.h>
37 #include <wx/propgrid/property.h>
38 #include <wx/propgrid/props.h>
39 DCPOMATIC_ENABLE_WARNINGS
40 #include <boost/bind/bind.hpp>
41
42
43 using std::string;
44 using std::vector;
45 using boost::bind;
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;
51 #endif
52 using dcp::locale_convert;
53
54
55
56 ContentAdvancedDialog::ContentAdvancedDialog (wxWindow* parent, shared_ptr<Content> content)
57         : wxDialog (parent, wxID_ANY, _("Advanced content settings"))
58         , _content (content)
59 {
60         auto sizer = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
61
62         int r = 0;
63
64         wxClientDC dc (this);
65         auto size = dc.GetTextExtent (wxT ("A quite long name"));
66 #ifdef __WXGTK3__
67         size.SetWidth (size.GetWidth() + 64);
68 #endif
69         size.SetHeight (-1);
70
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));
78         ++r;
79
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));
83         } else {
84                 video_frame_rate_label = add_label_to_sizer (sizer, this, _("Video frame rate that content was prepared for"), true, wxGBPosition(r, 0));
85         }
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));
91         ++r;
92
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);
99         ++r;
100
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));
103         ++r;
104
105         auto overall = new wxBoxSizer (wxVERTICAL);
106         overall->Add (sizer, 1, wxALL, DCPOMATIC_DIALOG_BORDER);
107         auto buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
108         if (buttons) {
109                 overall->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
110         }
111
112         SetSizerAndFit (overall);
113
114         ignore_video->Enable (static_cast<bool>(_content->video));
115         ignore_video->SetValue (_content->video ? !content->video->use() : false);
116         setup_filters ();
117
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);
121
122         auto vfr = _content->video_frame_rate ();
123         if (vfr) {
124                 _video_frame_rate->SetValue (std_to_wx(locale_convert<string>(*vfr)));
125         }
126
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);
129
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));
136
137         setup_sensitivity ();
138 }
139
140
141 void
142 ContentAdvancedDialog::ignore_video_changed (wxCommandEvent& ev)
143 {
144          if (_content->video) {
145                  _content->video->set_use (!ev.IsChecked());
146          }
147 }
148
149
150 void
151 ContentAdvancedDialog::setup_filters ()
152 {
153         auto fcs = dynamic_pointer_cast<FFmpegContent>(_content);
154         if (!fcs) {
155                 checked_set (_filters, _("None"));
156                 _filters->Enable (false);
157                 _filters_button->Enable (false);
158                 return;
159         }
160
161         auto p = Filter::ffmpeg_string (fcs->filters());
162         if (p.empty()) {
163                 checked_set (_filters, _("None"));
164         } else {
165                 if (p.length() > 25) {
166                         p = p.substr(0, 25) + "...";
167                 }
168                 checked_set (_filters, p);
169         }
170 }
171
172
173 void
174 ContentAdvancedDialog::edit_filters ()
175 {
176         auto fcs = dynamic_pointer_cast<FFmpegContent>(_content);
177         if (!fcs) {
178                 return;
179         }
180
181         auto d = new FilterDialog (this, fcs->filters());
182         d->ActiveChanged.connect (bind(&ContentAdvancedDialog::filters_changed, this, _1));
183         d->ShowModal ();
184         d->Destroy ();
185 }
186
187
188 void
189 ContentAdvancedDialog::filters_changed (vector<Filter const *> filters)
190 {
191         auto fcs = dynamic_pointer_cast<FFmpegContent>(_content);
192         if (!fcs) {
193                 return;
194         }
195
196         fcs->set_filters (filters);
197         setup_filters ();
198 }
199
200
201 void
202 ContentAdvancedDialog::set_video_frame_rate ()
203 {
204         if (_video_frame_rate->GetValue() != wxT("")) {
205                 _content->set_video_frame_rate (locale_convert<double>(wx_to_std(_video_frame_rate->GetValue())));
206         } else {
207                 _content->unset_video_frame_rate ();
208         }
209
210         _set_video_frame_rate->Enable (false);
211 }
212
213
214 void
215 ContentAdvancedDialog::video_frame_rate_changed ()
216 {
217        bool enable = true;
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.
220        */
221        if (_video_frame_rate->GetValue() == wxT("") && (dynamic_pointer_cast<DCPContent>(_content) || dynamic_pointer_cast<FFmpegContent>(_content))) {
222                enable = false;
223        }
224
225        _set_video_frame_rate->Enable (enable);
226 }
227
228
229 void
230 ContentAdvancedDialog::setup_sensitivity ()
231 {
232         _burnt_subtitle->Enable (static_cast<bool>(_content->video));
233         _burnt_subtitle_language->enable (_content->video && _burnt_subtitle->GetValue());
234 }
235
236
237 void
238 ContentAdvancedDialog::burnt_subtitle_changed ()
239 {
240         setup_sensitivity ();
241 }
242
243
244 void
245 ContentAdvancedDialog::burnt_subtitle_language_changed ()
246 {
247         DCPOMATIC_ASSERT (_content->video);
248         _content->video->set_burnt_subtitle_language (_burnt_subtitle_language->get());
249 }
250