Move DCP panel code into its own source file.
[dcpomatic.git] / src / wx / dcp_panel.cc
1 /*
2     Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "dcp_panel.h"
21 #include "wx_util.h"
22 #include "isdcf_metadata_dialog.h"
23 #include "lib/ratio.h"
24 #include "lib/scaler.h"
25 #include "lib/config.h"
26 #include "lib/dcp_content_type.h"
27 #include "lib/util.h"
28 #include "lib/film.h"
29 #include "lib/ffmpeg_content.h"
30 #include <wx/wx.h>
31 #include <wx/notebook.h>
32 #include <wx/gbsizer.h>
33 #include <wx/spinctrl.h>
34 #include <boost/lexical_cast.hpp>
35
36 using std::list;
37 using std::string;
38 using std::vector;
39 using boost::lexical_cast;
40 using boost::shared_ptr;
41
42 DCPPanel::DCPPanel (wxNotebook* n, boost::shared_ptr<Film> f)
43         : _film (f)
44         , _generally_sensitive (true)
45 {
46         _panel = new wxPanel (n);
47         _sizer = new wxBoxSizer (wxVERTICAL);
48         _panel->SetSizer (_sizer);
49
50         wxGridBagSizer* grid = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
51         _sizer->Add (grid, 0, wxEXPAND | wxALL, 8);
52
53         int r = 0;
54         
55         add_label_to_grid_bag_sizer (grid, _panel, _("Name"), true, wxGBPosition (r, 0));
56         _name = new wxTextCtrl (_panel, wxID_ANY);
57         grid->Add (_name, wxGBPosition(r, 1), wxDefaultSpan, wxEXPAND | wxLEFT | wxRIGHT);
58         ++r;
59         
60         add_label_to_grid_bag_sizer (grid, _panel, _("DCP Name"), true, wxGBPosition (r, 0));
61         _dcp_name = new wxStaticText (_panel, wxID_ANY, wxT (""));
62         grid->Add (_dcp_name, wxGBPosition(r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
63         ++r;
64
65         int flags = wxALIGN_CENTER_VERTICAL;
66 #ifdef __WXOSX__
67         flags |= wxALIGN_RIGHT;
68 #endif  
69
70         _use_isdcf_name = new wxCheckBox (_panel, wxID_ANY, _("Use ISDCF name"));
71         grid->Add (_use_isdcf_name, wxGBPosition (r, 0), wxDefaultSpan, flags);
72         _edit_isdcf_button = new wxButton (_panel, wxID_ANY, _("Details..."));
73         grid->Add (_edit_isdcf_button, wxGBPosition (r, 1), wxDefaultSpan);
74         ++r;
75
76         add_label_to_grid_bag_sizer (grid, _panel, _("Container"), true, wxGBPosition (r, 0));
77         _container = new wxChoice (_panel, wxID_ANY);
78         grid->Add (_container, wxGBPosition (r, 1), wxDefaultSpan, wxEXPAND);
79         ++r;
80
81         add_label_to_grid_bag_sizer (grid, _panel, _("Content Type"), true, wxGBPosition (r, 0));
82         _dcp_content_type = new wxChoice (_panel, wxID_ANY);
83         grid->Add (_dcp_content_type, wxGBPosition (r, 1));
84         ++r;
85
86         {
87                 add_label_to_grid_bag_sizer (grid, _panel, _("Frame Rate"), true, wxGBPosition (r, 0));
88                 _frame_rate_sizer = new wxBoxSizer (wxHORIZONTAL);
89                 _frame_rate_choice = new wxChoice (_panel, wxID_ANY);
90                 _frame_rate_sizer->Add (_frame_rate_choice, 1, wxALIGN_CENTER_VERTICAL);
91                 _frame_rate_spin = new wxSpinCtrl (_panel, wxID_ANY);
92                 _frame_rate_sizer->Add (_frame_rate_spin, 1, wxALIGN_CENTER_VERTICAL);
93                 setup_frame_rate_widget ();
94                 _best_frame_rate = new wxButton (_panel, wxID_ANY, _("Use best"));
95                 _frame_rate_sizer->Add (_best_frame_rate, 1, wxALIGN_CENTER_VERTICAL | wxEXPAND);
96                 grid->Add (_frame_rate_sizer, wxGBPosition (r, 1));
97         }
98         ++r;
99
100         _burn_subtitles = new wxCheckBox (_panel, wxID_ANY, _("Burn subtitles into image"));
101         grid->Add (_burn_subtitles, wxGBPosition (r, 0), wxGBSpan (1, 2));
102         ++r;
103
104         _signed = new wxCheckBox (_panel, wxID_ANY, _("Signed"));
105         grid->Add (_signed, wxGBPosition (r, 0), wxGBSpan (1, 2));
106         ++r;
107         
108         _encrypted = new wxCheckBox (_panel, wxID_ANY, _("Encrypted"));
109         grid->Add (_encrypted, wxGBPosition (r, 0), wxGBSpan (1, 2));
110         ++r;
111
112         add_label_to_grid_bag_sizer (grid, _panel, _("Audio channels"), true, wxGBPosition (r, 0));
113         _audio_channels = new wxSpinCtrl (_panel, wxID_ANY);
114         grid->Add (_audio_channels, wxGBPosition (r, 1));
115         ++r;
116
117         _three_d = new wxCheckBox (_panel, wxID_ANY, _("3D"));
118         grid->Add (_three_d, wxGBPosition (r, 0), wxGBSpan (1, 2));
119         ++r;
120
121         add_label_to_grid_bag_sizer (grid, _panel, _("Resolution"), true, wxGBPosition (r, 0));
122         _resolution = new wxChoice (_panel, wxID_ANY);
123         grid->Add (_resolution, wxGBPosition (r, 1));
124         ++r;
125
126         {
127                 add_label_to_grid_bag_sizer (grid, _panel, _("JPEG2000 bandwidth"), true, wxGBPosition (r, 0));
128                 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
129                 _j2k_bandwidth = new wxSpinCtrl (_panel, wxID_ANY);
130                 s->Add (_j2k_bandwidth, 1);
131                 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
132                 grid->Add (s, wxGBPosition (r, 1));
133         }
134         ++r;
135
136         add_label_to_grid_bag_sizer (grid, _panel, _("Standard"), true, wxGBPosition (r, 0));
137         _standard = new wxChoice (_panel, wxID_ANY);
138         grid->Add (_standard, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
139         ++r;
140
141         add_label_to_grid_bag_sizer (grid, _panel, _("Scaler"), true, wxGBPosition (r, 0));
142         _scaler = new wxChoice (_panel, wxID_ANY);
143         grid->Add (_scaler, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
144         ++r;
145
146         _name->Bind             (wxEVT_COMMAND_TEXT_UPDATED,          boost::bind (&DCPPanel::name_changed, this));
147         _use_isdcf_name->Bind   (wxEVT_COMMAND_CHECKBOX_CLICKED,      boost::bind (&DCPPanel::use_isdcf_name_toggled, this));
148         _edit_isdcf_button->Bind(wxEVT_COMMAND_BUTTON_CLICKED,        boost::bind (&DCPPanel::edit_isdcf_button_clicked, this));
149         _container->Bind        (wxEVT_COMMAND_CHOICE_SELECTED,       boost::bind (&DCPPanel::container_changed, this));
150         _scaler->Bind           (wxEVT_COMMAND_CHOICE_SELECTED,       boost::bind (&DCPPanel::scaler_changed, this));
151         _dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED,       boost::bind (&DCPPanel::dcp_content_type_changed, this));
152         _frame_rate_choice->Bind(wxEVT_COMMAND_CHOICE_SELECTED,       boost::bind (&DCPPanel::frame_rate_choice_changed, this));
153         _frame_rate_spin->Bind  (wxEVT_COMMAND_SPINCTRL_UPDATED,      boost::bind (&DCPPanel::frame_rate_spin_changed, this));
154         _best_frame_rate->Bind  (wxEVT_COMMAND_BUTTON_CLICKED,        boost::bind (&DCPPanel::best_frame_rate_clicked, this));
155         _burn_subtitles->Bind   (wxEVT_COMMAND_CHECKBOX_CLICKED,      boost::bind (&DCPPanel::burn_subtitles_toggled, this));
156         _signed->Bind           (wxEVT_COMMAND_CHECKBOX_CLICKED,      boost::bind (&DCPPanel::signed_toggled, this));
157         _encrypted->Bind        (wxEVT_COMMAND_CHECKBOX_CLICKED,      boost::bind (&DCPPanel::encrypted_toggled, this));
158         _audio_channels->Bind   (wxEVT_COMMAND_SPINCTRL_UPDATED,      boost::bind (&DCPPanel::audio_channels_changed, this));
159         _j2k_bandwidth->Bind    (wxEVT_COMMAND_SPINCTRL_UPDATED,      boost::bind (&DCPPanel::j2k_bandwidth_changed, this));
160         _resolution->Bind       (wxEVT_COMMAND_CHOICE_SELECTED,       boost::bind (&DCPPanel::resolution_changed, this));
161         _three_d->Bind          (wxEVT_COMMAND_CHECKBOX_CLICKED,      boost::bind (&DCPPanel::three_d_changed, this));
162         _standard->Bind         (wxEVT_COMMAND_CHOICE_SELECTED,       boost::bind (&DCPPanel::standard_changed, this));
163
164         vector<Scaler const *> const sc = Scaler::all ();
165         for (vector<Scaler const *>::const_iterator i = sc.begin(); i != sc.end(); ++i) {
166                 _scaler->Append (std_to_wx ((*i)->name()));
167         }
168
169         vector<Ratio const *> const ratio = Ratio::all ();
170         for (vector<Ratio const *>::const_iterator i = ratio.begin(); i != ratio.end(); ++i) {
171                 _container->Append (std_to_wx ((*i)->nickname ()));
172         }
173
174         vector<DCPContentType const *> const ct = DCPContentType::all ();
175         for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) {
176                 _dcp_content_type->Append (std_to_wx ((*i)->pretty_name ()));
177         }
178
179         list<int> const dfr = Config::instance()->allowed_dcp_frame_rates ();
180         for (list<int>::const_iterator i = dfr.begin(); i != dfr.end(); ++i) {
181                 _frame_rate_choice->Append (std_to_wx (boost::lexical_cast<string> (*i)));
182         }
183
184         _audio_channels->SetRange (0, MAX_DCP_AUDIO_CHANNELS);
185         _j2k_bandwidth->SetRange (1, Config::instance()->maximum_j2k_bandwidth() / 1000000);
186         _frame_rate_spin->SetRange (1, 480);
187
188         _resolution->Append (_("2K"));
189         _resolution->Append (_("4K"));
190
191         _standard->Append (_("SMPTE"));
192         _standard->Append (_("Interop"));
193
194         Config::instance()->Changed.connect (boost::bind (&DCPPanel::config_changed, this));
195 }
196
197 void
198 DCPPanel::name_changed ()
199 {
200         if (!_film) {
201                 return;
202         }
203
204         _film->set_name (string (_name->GetValue().mb_str()));
205 }
206
207 void
208 DCPPanel::j2k_bandwidth_changed ()
209 {
210         if (!_film) {
211                 return;
212         }
213         
214         _film->set_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
215 }
216
217 void
218 DCPPanel::signed_toggled ()
219 {
220         if (!_film) {
221                 return;
222         }
223
224         _film->set_signed (_signed->GetValue ());
225 }
226
227 void
228 DCPPanel::burn_subtitles_toggled ()
229 {
230         if (!_film) {
231                 return;
232         }
233
234         _film->set_burn_subtitles (_burn_subtitles->GetValue ());
235 }
236
237 void
238 DCPPanel::encrypted_toggled ()
239 {
240         if (!_film) {
241                 return;
242         }
243
244         _film->set_encrypted (_encrypted->GetValue ());
245 }
246                                
247 /** Called when the frame rate choice widget has been changed */
248 void
249 DCPPanel::frame_rate_choice_changed ()
250 {
251         if (!_film) {
252                 return;
253         }
254
255         _film->set_video_frame_rate (
256                 boost::lexical_cast<int> (
257                         wx_to_std (_frame_rate_choice->GetString (_frame_rate_choice->GetSelection ()))
258                         )
259                 );
260 }
261
262 /** Called when the frame rate spin widget has been changed */
263 void
264 DCPPanel::frame_rate_spin_changed ()
265 {
266         if (!_film) {
267                 return;
268         }
269
270         _film->set_video_frame_rate (_frame_rate_spin->GetValue ());
271 }
272
273 void
274 DCPPanel::audio_channels_changed ()
275 {
276         if (!_film) {
277                 return;
278         }
279
280         _film->set_audio_channels (_audio_channels->GetValue ());
281 }
282
283 void
284 DCPPanel::resolution_changed ()
285 {
286         if (!_film) {
287                 return;
288         }
289
290         _film->set_resolution (_resolution->GetSelection() == 0 ? RESOLUTION_2K : RESOLUTION_4K);
291 }
292
293 void
294 DCPPanel::standard_changed ()
295 {
296         if (!_film) {
297                 return;
298         }
299
300         _film->set_interop (_standard->GetSelection() == 1);
301 }
302
303 void
304 DCPPanel::film_changed (int p)
305 {
306         switch (p) {
307         case Film::NONE:
308                 break;
309         case Film::CONTAINER:
310                 setup_container ();
311                 break;
312         case Film::NAME:
313                 checked_set (_name, _film->name());
314                 setup_dcp_name ();
315                 break;
316         case Film::DCP_CONTENT_TYPE:
317                 checked_set (_dcp_content_type, DCPContentType::as_index (_film->dcp_content_type ()));
318                 setup_dcp_name ();
319                 break;
320         case Film::SCALER:
321                 checked_set (_scaler, Scaler::as_index (_film->scaler ()));
322                 break;
323         case Film::BURN_SUBTITLES:
324                 checked_set (_burn_subtitles, _film->burn_subtitles ());
325                 break;
326         case Film::SIGNED:
327                 checked_set (_signed, _film->is_signed ());
328                 break;
329         case Film::ENCRYPTED:
330                 checked_set (_encrypted, _film->encrypted ());
331                 if (_film->encrypted ()) {
332                         _film->set_signed (true);
333                         _signed->Enable (false);
334                 } else {
335                         _signed->Enable (_generally_sensitive);
336                 }
337                 break;
338         case Film::RESOLUTION:
339                 checked_set (_resolution, _film->resolution() == RESOLUTION_2K ? 0 : 1);
340                 setup_dcp_name ();
341                 break;
342         case Film::J2K_BANDWIDTH:
343                 checked_set (_j2k_bandwidth, _film->j2k_bandwidth() / 1000000);
344                 break;
345         case Film::USE_ISDCF_NAME:
346                 checked_set (_use_isdcf_name, _film->use_isdcf_name ());
347                 setup_dcp_name ();
348                 break;
349         case Film::ISDCF_METADATA:
350                 setup_dcp_name ();
351                 break;
352         case Film::VIDEO_FRAME_RATE:
353         {
354                 bool done = false;
355                 for (unsigned int i = 0; i < _frame_rate_choice->GetCount(); ++i) {
356                         if (wx_to_std (_frame_rate_choice->GetString(i)) == boost::lexical_cast<string> (_film->video_frame_rate())) {
357                                 checked_set (_frame_rate_choice, i);
358                                 done = true;
359                                 break;
360                         }
361                 }
362
363                 if (!done) {
364                         checked_set (_frame_rate_choice, -1);
365                 }
366
367                 _frame_rate_spin->SetValue (_film->video_frame_rate ());
368
369                 _best_frame_rate->Enable (_film->best_video_frame_rate () != _film->video_frame_rate ());
370                 break;
371         }
372         case Film::AUDIO_CHANNELS:
373                 checked_set (_audio_channels, _film->audio_channels ());
374                 setup_dcp_name ();
375                 break;
376         case Film::THREE_D:
377                 checked_set (_three_d, _film->three_d ());
378                 setup_dcp_name ();
379                 break;
380         case Film::INTEROP:
381                 checked_set (_standard, _film->interop() ? 1 : 0);
382                 break;
383         default:
384                 break;
385         }
386 }
387
388 void
389 DCPPanel::film_content_changed (int property)
390 {
391         if (property == FFmpegContentProperty::AUDIO_STREAM || property == SubtitleContentProperty::USE_SUBTITLES) {
392                 setup_dcp_name ();
393         }
394 }
395
396
397 void
398 DCPPanel::setup_container ()
399 {
400         int n = 0;
401         vector<Ratio const *> ratios = Ratio::all ();
402         vector<Ratio const *>::iterator i = ratios.begin ();
403         while (i != ratios.end() && *i != _film->container ()) {
404                 ++i;
405                 ++n;
406         }
407         
408         if (i == ratios.end()) {
409                 checked_set (_container, -1);
410         } else {
411                 checked_set (_container, n);
412         }
413         
414         setup_dcp_name ();
415 }       
416
417 /** Called when the container widget has been changed */
418 void
419 DCPPanel::container_changed ()
420 {
421         if (!_film) {
422                 return;
423         }
424
425         int const n = _container->GetSelection ();
426         if (n >= 0) {
427                 vector<Ratio const *> ratios = Ratio::all ();
428                 assert (n < int (ratios.size()));
429                 _film->set_container (ratios[n]);
430         }
431 }
432
433 /** Called when the DCP content type widget has been changed */
434 void
435 DCPPanel::dcp_content_type_changed ()
436 {
437         if (!_film) {
438                 return;
439         }
440
441         int const n = _dcp_content_type->GetSelection ();
442         if (n != wxNOT_FOUND) {
443                 _film->set_dcp_content_type (DCPContentType::from_index (n));
444         }
445 }
446
447 void
448 DCPPanel::set_film (shared_ptr<Film> film)
449 {
450         _film = film;
451         
452         film_changed (Film::NAME);
453         film_changed (Film::USE_ISDCF_NAME);
454         film_changed (Film::CONTENT);
455         film_changed (Film::DCP_CONTENT_TYPE);
456         film_changed (Film::CONTAINER);
457         film_changed (Film::RESOLUTION);
458         film_changed (Film::SCALER);
459         film_changed (Film::SIGNED);
460         film_changed (Film::BURN_SUBTITLES);
461         film_changed (Film::ENCRYPTED);
462         film_changed (Film::J2K_BANDWIDTH);
463         film_changed (Film::ISDCF_METADATA);
464         film_changed (Film::VIDEO_FRAME_RATE);
465         film_changed (Film::AUDIO_CHANNELS);
466         film_changed (Film::SEQUENCE_VIDEO);
467         film_changed (Film::THREE_D);
468         film_changed (Film::INTEROP);
469 }
470
471 void
472 DCPPanel::set_general_sensitivity (bool s)
473 {
474         _name->Enable (s);
475         _use_isdcf_name->Enable (s);
476         _edit_isdcf_button->Enable (s);
477         _dcp_content_type->Enable (s);
478
479         bool si = s;
480         if (_film && _film->encrypted ()) {
481                 si = false;
482         }
483         _burn_subtitles->Enable (s);
484         _signed->Enable (si);
485         
486         _encrypted->Enable (s);
487         _frame_rate_choice->Enable (s);
488         _frame_rate_spin->Enable (s);
489         _audio_channels->Enable (s);
490         _j2k_bandwidth->Enable (s);
491         _container->Enable (s);
492         _best_frame_rate->Enable (s && _film && _film->best_video_frame_rate () != _film->video_frame_rate ());
493         _resolution->Enable (s);
494         _scaler->Enable (s);
495         _three_d->Enable (s);
496         _standard->Enable (s);
497 }
498
499 /** Called when the scaler widget has been changed */
500 void
501 DCPPanel::scaler_changed ()
502 {
503         if (!_film) {
504                 return;
505         }
506
507         int const n = _scaler->GetSelection ();
508         if (n >= 0) {
509                 _film->set_scaler (Scaler::from_index (n));
510         }
511 }
512
513 void
514 DCPPanel::use_isdcf_name_toggled ()
515 {
516         if (!_film) {
517                 return;
518         }
519
520         _film->set_use_isdcf_name (_use_isdcf_name->GetValue ());
521 }
522
523 void
524 DCPPanel::edit_isdcf_button_clicked ()
525 {
526         if (!_film) {
527                 return;
528         }
529
530         ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, _film->isdcf_metadata ());
531         d->ShowModal ();
532         _film->set_isdcf_metadata (d->isdcf_metadata ());
533         d->Destroy ();
534 }
535
536 void
537 DCPPanel::setup_dcp_name ()
538 {
539         string s = _film->dcp_name (true);
540         if (s.length() > 28) {
541                 _dcp_name->SetLabel (std_to_wx (s.substr (0, 28)) + N_("..."));
542                 _dcp_name->SetToolTip (std_to_wx (s));
543         } else {
544                 _dcp_name->SetLabel (std_to_wx (s));
545         }
546 }
547
548 void
549 DCPPanel::best_frame_rate_clicked ()
550 {
551         if (!_film) {
552                 return;
553         }
554         
555         _film->set_video_frame_rate (_film->best_video_frame_rate ());
556 }
557
558 void
559 DCPPanel::three_d_changed ()
560 {
561         if (!_film) {
562                 return;
563         }
564
565         _film->set_three_d (_three_d->GetValue ());
566 }
567
568 void
569 DCPPanel::config_changed ()
570 {
571         _j2k_bandwidth->SetRange (1, Config::instance()->maximum_j2k_bandwidth() / 1000000);
572         setup_frame_rate_widget ();
573 }
574
575 void
576 DCPPanel::setup_frame_rate_widget ()
577 {
578         if (Config::instance()->allow_any_dcp_frame_rate ()) {
579                 _frame_rate_choice->Hide ();
580                 _frame_rate_spin->Show ();
581         } else {
582                 _frame_rate_choice->Show ();
583                 _frame_rate_spin->Hide ();
584         }
585
586         _frame_rate_sizer->Layout ();
587 }