9f2a45106805a4c3995418347825114a6a5d605e
[dcpomatic.git] / src / wx / content_advanced_dialog.cc
1 /*
2     Copyright (C) 2020 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 "static_text.h"
26 #include "wx_util.h"
27 #include "lib/content.h"
28 #include "lib/dcp_content.h"
29 #include "lib/filter.h"
30 #include "lib/ffmpeg_content.h"
31 #include "lib/image_content.h"
32 #include "lib/video_content.h"
33 #include <wx/gbsizer.h>
34 #include <boost/bind.hpp>
35
36
37 using std::string;
38 using std::vector;
39 using boost::bind;
40 using boost::dynamic_pointer_cast;
41 using boost::optional;
42 using boost::shared_ptr;
43 #if BOOST_VERSION >= 106100
44 using namespace boost::placeholders;
45 #endif
46 using dcp::locale_convert;
47
48
49
50 ContentAdvancedDialog::ContentAdvancedDialog (wxWindow* parent, shared_ptr<Content> content)
51         : wxDialog (parent, wxID_ANY, _("Advanced content settings"))
52         , _content (content)
53 {
54         wxGridBagSizer* sizer = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
55
56         int r = 0;
57
58         wxClientDC dc (this);
59         wxSize size = dc.GetTextExtent (wxT ("A quite long name"));
60 #ifdef __WXGTK3__
61         size.SetWidth (size.GetWidth() + 64);
62 #endif
63         size.SetHeight (-1);
64
65         add_label_to_sizer (sizer, this, _("Video filters"), true, wxGBPosition(r, 0));
66         _filters = new StaticText (this, _("None"), wxDefaultPosition, size);
67         _filters_button = new Button (this, _("Edit..."));
68         wxBoxSizer* filters = new wxBoxSizer (wxHORIZONTAL);
69         filters->Add (_filters, 1, wxALL | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_GAP);
70         filters->Add (_filters_button, 0, wxALL, DCPOMATIC_SIZER_GAP);
71         sizer->Add (filters, wxGBPosition(r, 1), wxGBSpan(1, 2));
72         ++r;
73
74         wxStaticText* video_frame_rate_label;
75         if (_content->video) {
76                 video_frame_rate_label = add_label_to_sizer (sizer, this, _("Override detected video frame rate"), true, wxGBPosition(r, 0));
77         } else {
78                 video_frame_rate_label = add_label_to_sizer (sizer, this, _("Video frame rate that content was prepared for"), true, wxGBPosition(r, 0));
79         }
80         _video_frame_rate = new wxTextCtrl (this, wxID_ANY);
81         sizer->Add (_video_frame_rate, wxGBPosition(r, 1));
82         _set_video_frame_rate = new Button (this, _("Set"));
83         _set_video_frame_rate->Enable (false);
84         sizer->Add (_set_video_frame_rate, wxGBPosition(r, 2));
85         ++r;
86
87         wxCheckBox* ignore_video = new wxCheckBox (this, wxID_ANY, _("Ignore this content's video and use only audio, subtitles and closed captions"));
88         sizer->Add (ignore_video, wxGBPosition(r, 0), wxGBSpan(1, 3));
89         ++r;
90
91         wxSizer* overall = new wxBoxSizer (wxVERTICAL);
92         overall->Add (sizer, 1, wxALL, DCPOMATIC_DIALOG_BORDER);
93         wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
94         if (buttons) {
95                 overall->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
96         }
97
98         SetSizerAndFit (overall);
99
100         ignore_video->Enable (static_cast<bool>(_content->video));
101         ignore_video->SetValue (_content->video ? !content->video->use() : false);
102         setup_filters ();
103
104         bool const single_frame_image_content = dynamic_pointer_cast<const ImageContent>(_content) && _content->number_of_paths() == 1;
105         video_frame_rate_label->Enable (!single_frame_image_content);
106         _video_frame_rate->Enable (!single_frame_image_content);
107
108         optional<double> vfr = _content->video_frame_rate ();
109         if (vfr) {
110                 _video_frame_rate->SetValue (std_to_wx(locale_convert<string>(*vfr)));
111         }
112
113         ignore_video->Bind (wxEVT_CHECKBOX, bind(&ContentAdvancedDialog::ignore_video_changed, this, _1));
114         _filters_button->Bind (wxEVT_BUTTON, bind(&ContentAdvancedDialog::edit_filters, this));
115         _set_video_frame_rate->Bind (wxEVT_BUTTON, bind(&ContentAdvancedDialog::set_video_frame_rate, this));
116         _video_frame_rate->Bind (wxEVT_TEXT, boost::bind(&ContentAdvancedDialog::video_frame_rate_changed, this));
117 }
118
119
120 void
121 ContentAdvancedDialog::ignore_video_changed (wxCommandEvent& ev)
122 {
123          if (_content->video) {
124                  _content->video->set_use (!ev.IsChecked());
125          }
126 }
127
128
129 void
130 ContentAdvancedDialog::setup_filters ()
131 {
132         shared_ptr<FFmpegContent> fcs = dynamic_pointer_cast<FFmpegContent>(_content);
133         if (!fcs) {
134                 checked_set (_filters, _("None"));
135                 _filters->Enable (false);
136                 _filters_button->Enable (false);
137                 return;
138         }
139
140         string p = Filter::ffmpeg_string (fcs->filters());
141         if (p.empty()) {
142                 checked_set (_filters, _("None"));
143         } else {
144                 if (p.length() > 25) {
145                         p = p.substr(0, 25) + "...";
146                 }
147                 checked_set (_filters, p);
148         }
149 }
150
151
152 void
153 ContentAdvancedDialog::edit_filters ()
154 {
155         shared_ptr<FFmpegContent> fcs = dynamic_pointer_cast<FFmpegContent>(_content);
156         if (!fcs) {
157                 return;
158         }
159
160         FilterDialog* d = new FilterDialog (this, fcs->filters());
161         d->ActiveChanged.connect (bind(&ContentAdvancedDialog::filters_changed, this, _1));
162         d->ShowModal ();
163         d->Destroy ();
164 }
165
166
167 void
168 ContentAdvancedDialog::filters_changed (vector<Filter const *> filters)
169 {
170         shared_ptr<FFmpegContent> fcs = dynamic_pointer_cast<FFmpegContent>(_content);
171         if (!fcs) {
172                 return;
173         }
174
175         fcs->set_filters (filters);
176         setup_filters ();
177 }
178
179
180 void
181 ContentAdvancedDialog::set_video_frame_rate ()
182 {
183         if (_video_frame_rate->GetValue() != wxT("")) {
184                 _content->set_video_frame_rate (locale_convert<double>(wx_to_std(_video_frame_rate->GetValue())));
185         } else {
186                 _content->unset_video_frame_rate ();
187         }
188
189         _set_video_frame_rate->Enable (false);
190 }
191
192
193 void
194 ContentAdvancedDialog::video_frame_rate_changed ()
195 {
196        bool enable = true;
197        /* If the user clicks "set" now, with no frame rate entered, it would unset the video
198           frame rate in the selected content.  This can't be allowed for some content types.
199        */
200        if (_video_frame_rate->GetValue() == wxT("") && (dynamic_pointer_cast<DCPContent>(_content) || dynamic_pointer_cast<FFmpegContent>(_content))) {
201                enable = false;
202        }
203
204        _set_video_frame_rate->Enable (enable);
205 }
206