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