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