Clean up slightly and put encrypted checkbox into full mode.
[dcpomatic.git] / src / wx / dcp_panel.cc
1 /*
2     Copyright (C) 2012-2016 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 #include "dcp_panel.h"
22 #include "wx_util.h"
23 #include "key_dialog.h"
24 #include "isdcf_metadata_dialog.h"
25 #include "audio_dialog.h"
26 #include "focus_manager.h"
27 #include "lib/ratio.h"
28 #include "lib/config.h"
29 #include "lib/dcp_content_type.h"
30 #include "lib/util.h"
31 #include "lib/film.h"
32 #include "lib/ffmpeg_content.h"
33 #include "lib/audio_processor.h"
34 #include "lib/video_content.h"
35 #include "lib/text_content.h"
36 #include "lib/dcp_content.h"
37 #include "lib/audio_content.h"
38 #include <dcp/locale_convert.h>
39 #include <dcp/key.h>
40 #include <wx/wx.h>
41 #include <wx/notebook.h>
42 #include <wx/gbsizer.h>
43 #include <wx/spinctrl.h>
44 #include <boost/lexical_cast.hpp>
45 #include <boost/foreach.hpp>
46 #include <iostream>
47
48 using std::cout;
49 using std::list;
50 using std::string;
51 using std::vector;
52 using std::pair;
53 using std::max;
54 using std::make_pair;
55 using boost::lexical_cast;
56 using boost::shared_ptr;
57 using dcp::locale_convert;
58
59 DCPPanel::DCPPanel (wxNotebook* n, boost::shared_ptr<Film> film)
60         : _audio_dialog (0)
61         , _film (film)
62         , _generally_sensitive (true)
63 {
64         _panel = new wxPanel (n);
65         _sizer = new wxBoxSizer (wxVERTICAL);
66         _panel->SetSizer (_sizer);
67
68         _grid = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
69         _sizer->Add (_grid, 0, wxEXPAND | wxALL, 8);
70
71         _name_label = create_label (_panel, _("Name"), true);
72         _name = new wxTextCtrl (_panel, wxID_ANY);
73         FocusManager::instance()->add(_name);
74
75         _use_isdcf_name = new wxCheckBox (_panel, wxID_ANY, _("Use ISDCF name"));
76         _edit_isdcf_button = new wxButton (_panel, wxID_ANY, _("Details..."));
77         _copy_isdcf_name_button = new wxButton (_panel, wxID_ANY, _("Copy as name"));
78
79         /* wxST_ELLIPSIZE_MIDDLE works around a bug in GTK2 and/or wxWidgets, see
80            http://trac.wxwidgets.org/ticket/12539
81         */
82         _dcp_name = new wxStaticText (
83                 _panel, wxID_ANY, wxT (""), wxDefaultPosition, wxDefaultSize,
84                 wxALIGN_CENTRE_HORIZONTAL | wxST_NO_AUTORESIZE | wxST_ELLIPSIZE_MIDDLE
85                 );
86
87         _dcp_content_type_label = create_label (_panel, _("Content Type"), true);
88         _dcp_content_type = new wxChoice (_panel, wxID_ANY);
89
90         _signed = new wxCheckBox (_panel, wxID_ANY, _("Signed"));
91         _encrypted = new wxCheckBox (_panel, wxID_ANY, _("Encrypted"));
92
93         wxClientDC dc (_panel);
94         wxSize size = dc.GetTextExtent (wxT ("GGGGGGGG..."));
95         size.SetHeight (-1);
96
97         _key_label = create_label (_panel, _("Key"), true);
98         _key = new wxStaticText (_panel, wxID_ANY, "", wxDefaultPosition, size);
99         _edit_key = new wxButton (_panel, wxID_ANY, _("Edit..."));
100
101         _reels_label = create_label (_panel, _("Reels"), true);
102         _reel_type = new wxChoice (_panel, wxID_ANY);
103
104         _reel_length_label = create_label (_panel, _("Reel length"), true);
105         _reel_length = new wxSpinCtrl (_panel, wxID_ANY);
106         _reel_length_gb_label = create_label (_panel, _("GB"), false);
107
108         _standard_label = create_label (_panel, _("Standard"), true);
109         _standard = new wxChoice (_panel, wxID_ANY);
110
111         _upload_after_make_dcp = new wxCheckBox (_panel, wxID_ANY, _("Upload DCP to TMS after it is made"));
112
113         _notebook = new wxNotebook (_panel, wxID_ANY);
114         _sizer->Add (_notebook, 1, wxEXPAND | wxTOP, 6);
115
116         _notebook->AddPage (make_video_panel (), _("Video"), false);
117         _notebook->AddPage (make_audio_panel (), _("Audio"), false);
118
119         _name->Bind                  (wxEVT_TEXT,     boost::bind (&DCPPanel::name_changed, this));
120         _use_isdcf_name->Bind        (wxEVT_CHECKBOX, boost::bind (&DCPPanel::use_isdcf_name_toggled, this));
121         _edit_isdcf_button->Bind     (wxEVT_BUTTON,   boost::bind (&DCPPanel::edit_isdcf_button_clicked, this));
122         _copy_isdcf_name_button->Bind(wxEVT_BUTTON,   boost::bind (&DCPPanel::copy_isdcf_name_button_clicked, this));
123         _dcp_content_type->Bind      (wxEVT_CHOICE,   boost::bind (&DCPPanel::dcp_content_type_changed, this));
124         _signed->Bind                (wxEVT_CHECKBOX, boost::bind (&DCPPanel::signed_toggled, this));
125         _encrypted->Bind             (wxEVT_CHECKBOX, boost::bind (&DCPPanel::encrypted_toggled, this));
126         _edit_key->Bind              (wxEVT_BUTTON,   boost::bind (&DCPPanel::edit_key_clicked, this));
127         _reel_type->Bind             (wxEVT_CHOICE,   boost::bind (&DCPPanel::reel_type_changed, this));
128         _reel_length->Bind           (wxEVT_SPINCTRL, boost::bind (&DCPPanel::reel_length_changed, this));
129         _standard->Bind              (wxEVT_CHOICE,   boost::bind (&DCPPanel::standard_changed, this));
130         _upload_after_make_dcp->Bind (wxEVT_CHECKBOX, boost::bind (&DCPPanel::upload_after_make_dcp_changed, this));
131
132         BOOST_FOREACH (DCPContentType const * i, DCPContentType::all()) {
133                 _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
134         }
135
136         _reel_type->Append (_("Single reel"));
137         _reel_type->Append (_("Split by video content"));
138         /// TRANSLATORS: translate the word "Custom" here; do not include the "Reel|" prefix
139         _reel_type->Append (S_("Reel|Custom"));
140
141         _reel_length->SetRange (1, 64);
142
143         _standard->Append (_("SMPTE"));
144         _standard->Append (_("Interop"));
145
146         Config::instance()->Changed.connect (boost::bind (&DCPPanel::config_changed, this, _1));
147
148         add_to_grid ();
149 }
150
151 void
152 DCPPanel::add_to_grid ()
153 {
154         Config::Interface interface = Config::instance()->interface_complexity ();
155
156         int r = 0;
157
158         add_label_to_sizer (_grid, _name_label, true, wxGBPosition (r, 0));
159         _grid->Add (_name, wxGBPosition(r, 1), wxDefaultSpan, wxEXPAND | wxLEFT | wxRIGHT);
160         ++r;
161
162         int flags = wxALIGN_CENTER_VERTICAL;
163 #ifdef __WXOSX__
164         flags |= wxALIGN_RIGHT;
165 #endif
166
167         bool const full = interface == Config::INTERFACE_FULL;
168
169         _use_isdcf_name->Show (full);
170         _edit_isdcf_button->Show (full);
171         _copy_isdcf_name_button->Show (full);
172
173         if (full) {
174                 _grid->Add (_use_isdcf_name, wxGBPosition (r, 0), wxDefaultSpan, flags);
175                 {
176                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
177                         s->Add (_edit_isdcf_button, 1, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_X_GAP);
178                         s->Add (_copy_isdcf_name_button, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_X_GAP);
179                         _grid->Add (s, wxGBPosition (r, 1), wxDefaultSpan, wxEXPAND);
180                 }
181                 ++r;
182         }
183
184         _grid->Add (_dcp_name, wxGBPosition(r, 0), wxGBSpan (1, 2), wxALIGN_CENTER_VERTICAL | wxEXPAND);
185         ++r;
186
187         add_label_to_sizer (_grid, _dcp_content_type_label, true, wxGBPosition (r, 0));
188         _grid->Add (_dcp_content_type, wxGBPosition (r, 1));
189         ++r;
190
191         _signed->Show (full);
192         if (full) {
193                 _grid->Add (_signed, wxGBPosition (r, 0), wxGBSpan (1, 2));
194                 ++r;
195         }
196
197         _grid->Add (_encrypted, wxGBPosition (r, 0), wxGBSpan (1, 2));
198         ++r;
199
200
201         _key_label->Show (full);
202         _key->Show (full);
203         _edit_key->Show (full);
204         _reels_label->Show (full);
205         _reel_type->Show (full);
206         _reel_length_label->Show (full);
207         _reel_length->Show (full);
208         _reel_length_gb_label->Show (full);
209         _standard_label->Show (full);
210         _standard->Show (full);
211         _upload_after_make_dcp->Show (full);
212         _reencode_j2k->Show (full);
213         _encrypted->Show (full);
214
215         if (full) {
216                 add_label_to_sizer (_grid, _key_label, true, wxGBPosition (r, 0));
217                 {
218                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
219                         s->Add (_key, 1, wxALIGN_CENTER_VERTICAL);
220                         s->Add (_edit_key);
221                         _grid->Add (s, wxGBPosition (r, 1));
222                 }
223                 ++r;
224
225                 add_label_to_sizer (_grid, _reels_label, true, wxGBPosition (r, 0));
226                 _grid->Add (_reel_type, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
227                 ++r;
228
229                 add_label_to_sizer (_grid, _reel_length_label, true, wxGBPosition (r, 0));
230                 {
231                         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
232                         s->Add (_reel_length);
233                         add_label_to_sizer (s, _reel_length_gb_label, false);
234                         _grid->Add (s, wxGBPosition (r, 1));
235                 }
236                 ++r;
237
238                 add_label_to_sizer (_grid, _standard_label, true, wxGBPosition (r, 0));
239                 _grid->Add (_standard, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
240                 ++r;
241
242                 _grid->Add (_upload_after_make_dcp, wxGBPosition (r, 0), wxGBSpan (1, 2));
243                 ++r;
244         }
245 }
246
247 void
248 DCPPanel::edit_key_clicked ()
249 {
250         KeyDialog* d = new KeyDialog (_panel, _film->key ());
251         if (d->ShowModal () == wxID_OK) {
252                 _film->set_key (d->key ());
253         }
254         d->Destroy ();
255 }
256
257 void
258 DCPPanel::name_changed ()
259 {
260         if (!_film) {
261                 return;
262         }
263
264         _film->set_name (string (_name->GetValue().mb_str()));
265 }
266
267 void
268 DCPPanel::j2k_bandwidth_changed ()
269 {
270         if (!_film) {
271                 return;
272         }
273
274         _film->set_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
275 }
276
277 void
278 DCPPanel::signed_toggled ()
279 {
280         if (!_film) {
281                 return;
282         }
283
284         _film->set_signed (_signed->GetValue ());
285 }
286
287 void
288 DCPPanel::encrypted_toggled ()
289 {
290         if (!_film) {
291                 return;
292         }
293
294         _film->set_encrypted (_encrypted->GetValue ());
295 }
296
297 /** Called when the frame rate choice widget has been changed */
298 void
299 DCPPanel::frame_rate_choice_changed ()
300 {
301         if (!_film) {
302                 return;
303         }
304
305         _film->set_video_frame_rate (
306                 boost::lexical_cast<int> (
307                         wx_to_std (_frame_rate_choice->GetString (_frame_rate_choice->GetSelection ()))
308                         )
309                 );
310 }
311
312 /** Called when the frame rate spin widget has been changed */
313 void
314 DCPPanel::frame_rate_spin_changed ()
315 {
316         if (!_film) {
317                 return;
318         }
319
320         _film->set_video_frame_rate (_frame_rate_spin->GetValue ());
321 }
322
323 void
324 DCPPanel::audio_channels_changed ()
325 {
326         if (!_film) {
327                 return;
328         }
329
330         _film->set_audio_channels (locale_convert<int> (string_client_data (_audio_channels->GetClientObject (_audio_channels->GetSelection ()))));
331 }
332
333 void
334 DCPPanel::resolution_changed ()
335 {
336         if (!_film) {
337                 return;
338         }
339
340         _film->set_resolution (_resolution->GetSelection() == 0 ? RESOLUTION_2K : RESOLUTION_4K);
341 }
342
343 void
344 DCPPanel::standard_changed ()
345 {
346         if (!_film) {
347                 return;
348         }
349
350         _film->set_interop (_standard->GetSelection() == 1);
351 }
352
353 void
354 DCPPanel::upload_after_make_dcp_changed ()
355 {
356         if (!_film) {
357                 return;
358         }
359
360         _film->set_upload_after_make_dcp (_upload_after_make_dcp->GetValue ());
361 }
362
363 void
364 DCPPanel::film_changed (int p)
365 {
366         switch (p) {
367         case Film::NONE:
368                 break;
369         case Film::CONTAINER:
370                 setup_container ();
371                 break;
372         case Film::NAME:
373                 checked_set (_name, _film->name());
374                 setup_dcp_name ();
375                 break;
376         case Film::DCP_CONTENT_TYPE:
377                 checked_set (_dcp_content_type, DCPContentType::as_index (_film->dcp_content_type ()));
378                 setup_dcp_name ();
379                 break;
380         case Film::SIGNED:
381                 checked_set (_signed, _film->is_signed ());
382                 break;
383         case Film::ENCRYPTED:
384                 checked_set (_encrypted, _film->encrypted ());
385                 if (_film->encrypted ()) {
386                         _film->set_signed (true);
387                         _signed->Enable (false);
388                         _key->Enable (_generally_sensitive);
389                         _edit_key->Enable (_generally_sensitive);
390                 } else {
391                         _signed->Enable (_generally_sensitive);
392                         _key->Enable (false);
393                         _edit_key->Enable (false);
394                 }
395                 break;
396         case Film::KEY:
397                 checked_set (_key, _film->key().hex().substr (0, 8) + "...");
398                 break;
399         case Film::RESOLUTION:
400                 checked_set (_resolution, _film->resolution() == RESOLUTION_2K ? 0 : 1);
401                 setup_container ();
402                 setup_dcp_name ();
403                 break;
404         case Film::J2K_BANDWIDTH:
405                 checked_set (_j2k_bandwidth, _film->j2k_bandwidth() / 1000000);
406                 break;
407         case Film::USE_ISDCF_NAME:
408         {
409                 checked_set (_use_isdcf_name, _film->use_isdcf_name ());
410                 setup_dcp_name ();
411                 _edit_isdcf_button->Enable (_film->use_isdcf_name ());
412                 break;
413         }
414         case Film::ISDCF_METADATA:
415                 setup_dcp_name ();
416                 break;
417         case Film::VIDEO_FRAME_RATE:
418         {
419                 bool done = false;
420                 for (unsigned int i = 0; i < _frame_rate_choice->GetCount(); ++i) {
421                         if (wx_to_std (_frame_rate_choice->GetString(i)) == boost::lexical_cast<string> (_film->video_frame_rate())) {
422                                 checked_set (_frame_rate_choice, i);
423                                 done = true;
424                                 break;
425                         }
426                 }
427
428                 if (!done) {
429                         checked_set (_frame_rate_choice, -1);
430                 }
431
432                 checked_set (_frame_rate_spin, _film->video_frame_rate ());
433
434                 _best_frame_rate->Enable (_film->best_video_frame_rate () != _film->video_frame_rate ());
435                 setup_dcp_name ();
436                 break;
437         }
438         case Film::AUDIO_CHANNELS:
439                 if (_film->audio_channels () < minimum_allowed_audio_channels ()) {
440                         _film->set_audio_channels (minimum_allowed_audio_channels ());
441                 } else {
442                         checked_set (_audio_channels, locale_convert<string> (max (minimum_allowed_audio_channels(), _film->audio_channels ())));
443                         setup_dcp_name ();
444                 }
445                 break;
446         case Film::THREE_D:
447                 checked_set (_three_d, _film->three_d ());
448                 setup_dcp_name ();
449                 break;
450         case Film::REENCODE_J2K:
451                 checked_set (_reencode_j2k, _film->reencode_j2k());
452                 break;
453         case Film::INTEROP:
454                 checked_set (_standard, _film->interop() ? 1 : 0);
455                 setup_dcp_name ();
456                 break;
457         case Film::AUDIO_PROCESSOR:
458                 if (_film->audio_processor ()) {
459                         checked_set (_audio_processor, _film->audio_processor()->id());
460                 } else {
461                         checked_set (_audio_processor, 0);
462                 }
463                 setup_audio_channels_choice (_audio_channels, minimum_allowed_audio_channels ());
464                 film_changed (Film::AUDIO_CHANNELS);
465                 break;
466         case Film::REEL_TYPE:
467                 checked_set (_reel_type, _film->reel_type ());
468                 _reel_length->Enable (_film->reel_type() == REELTYPE_BY_LENGTH);
469                 break;
470         case Film::REEL_LENGTH:
471                 checked_set (_reel_length, _film->reel_length() / 1000000000LL);
472                 break;
473         case Film::UPLOAD_AFTER_MAKE_DCP:
474                 checked_set (_upload_after_make_dcp, _film->upload_after_make_dcp ());
475                 break;
476         case Film::CONTENT:
477                 setup_dcp_name ();
478                 break;
479         default:
480                 break;
481         }
482 }
483
484 void
485 DCPPanel::film_content_changed (int property)
486 {
487         if (property == AudioContentProperty::STREAMS ||
488             property == TextContentProperty::USE ||
489             property == TextContentProperty::BURN ||
490             property == VideoContentProperty::SCALE ||
491             property == DCPContentProperty::REFERENCE_VIDEO ||
492             property == DCPContentProperty::REFERENCE_AUDIO ||
493             property == DCPContentProperty::REFERENCE_TEXT) {
494                 setup_dcp_name ();
495                 setup_sensitivity ();
496         }
497 }
498
499
500 void
501 DCPPanel::setup_container ()
502 {
503         int n = 0;
504         vector<Ratio const *> ratios = Ratio::containers ();
505         vector<Ratio const *>::iterator i = ratios.begin ();
506         while (i != ratios.end() && *i != _film->container ()) {
507                 ++i;
508                 ++n;
509         }
510
511         if (i == ratios.end()) {
512                 checked_set (_container, -1);
513                 checked_set (_container_size, wxT (""));
514         } else {
515                 checked_set (_container, n);
516                 dcp::Size const size = fit_ratio_within (_film->container()->ratio(), _film->full_frame ());
517                 checked_set (_container_size, wxString::Format ("%dx%d", size.width, size.height));
518         }
519
520         setup_dcp_name ();
521 }
522
523 /** Called when the container widget has been changed */
524 void
525 DCPPanel::container_changed ()
526 {
527         if (!_film) {
528                 return;
529         }
530
531         int const n = _container->GetSelection ();
532         if (n >= 0) {
533                 vector<Ratio const *> ratios = Ratio::containers ();
534                 DCPOMATIC_ASSERT (n < int (ratios.size()));
535                 _film->set_container (ratios[n]);
536         }
537 }
538
539 /** Called when the DCP content type widget has been changed */
540 void
541 DCPPanel::dcp_content_type_changed ()
542 {
543         if (!_film) {
544                 return;
545         }
546
547         int const n = _dcp_content_type->GetSelection ();
548         if (n != wxNOT_FOUND) {
549                 _film->set_dcp_content_type (DCPContentType::from_index (n));
550         }
551 }
552
553 void
554 DCPPanel::set_film (shared_ptr<Film> film)
555 {
556         /* We are changing film, so destroy any audio dialog for the old one */
557         if (_audio_dialog) {
558                 _audio_dialog->Destroy ();
559                 _audio_dialog = 0;
560         }
561
562         _film = film;
563
564         film_changed (Film::NAME);
565         film_changed (Film::USE_ISDCF_NAME);
566         film_changed (Film::CONTENT);
567         film_changed (Film::DCP_CONTENT_TYPE);
568         film_changed (Film::CONTAINER);
569         film_changed (Film::RESOLUTION);
570         film_changed (Film::SIGNED);
571         film_changed (Film::ENCRYPTED);
572         film_changed (Film::KEY);
573         film_changed (Film::J2K_BANDWIDTH);
574         film_changed (Film::ISDCF_METADATA);
575         film_changed (Film::VIDEO_FRAME_RATE);
576         film_changed (Film::AUDIO_CHANNELS);
577         film_changed (Film::SEQUENCE);
578         film_changed (Film::THREE_D);
579         film_changed (Film::INTEROP);
580         film_changed (Film::AUDIO_PROCESSOR);
581         film_changed (Film::REEL_TYPE);
582         film_changed (Film::REEL_LENGTH);
583         film_changed (Film::UPLOAD_AFTER_MAKE_DCP);
584         film_changed (Film::REENCODE_J2K);
585
586         set_general_sensitivity(static_cast<bool>(_film));
587 }
588
589 void
590 DCPPanel::set_general_sensitivity (bool s)
591 {
592         _generally_sensitive = s;
593         setup_sensitivity ();
594 }
595
596 void
597 DCPPanel::setup_sensitivity ()
598 {
599         _name->Enable                   (_generally_sensitive);
600         _use_isdcf_name->Enable         (_generally_sensitive);
601         _edit_isdcf_button->Enable      (_generally_sensitive);
602         _dcp_content_type->Enable       (_generally_sensitive);
603         _copy_isdcf_name_button->Enable (_generally_sensitive);
604
605         bool si = _generally_sensitive;
606         if (_film && _film->encrypted ()) {
607                 si = false;
608         }
609         _signed->Enable (si);
610
611         _encrypted->Enable              (_generally_sensitive);
612         _key->Enable                    (_generally_sensitive && _film && _film->encrypted ());
613         _edit_key->Enable               (_generally_sensitive && _film && _film->encrypted ());
614         _reel_type->Enable              (_generally_sensitive && _film && !_film->references_dcp_video() && !_film->references_dcp_audio());
615         _reel_length->Enable            (_generally_sensitive && _film && _film->reel_type() == REELTYPE_BY_LENGTH);
616         _upload_after_make_dcp->Enable  (_generally_sensitive);
617         _frame_rate_choice->Enable      (_generally_sensitive && _film && !_film->references_dcp_video());
618         _frame_rate_spin->Enable        (_generally_sensitive && _film && !_film->references_dcp_video());
619         _audio_channels->Enable         (_generally_sensitive && _film && !_film->references_dcp_audio());
620         _audio_processor->Enable        (_generally_sensitive && _film && !_film->references_dcp_audio());
621         _j2k_bandwidth->Enable          (_generally_sensitive && _film && !_film->references_dcp_video());
622         _container->Enable              (_generally_sensitive && _film && !_film->references_dcp_video());
623         _best_frame_rate->Enable        (_generally_sensitive && _film && _film->best_video_frame_rate () != _film->video_frame_rate ());
624         _resolution->Enable             (_generally_sensitive && _film && !_film->references_dcp_video());
625         _three_d->Enable                (_generally_sensitive && _film && !_film->references_dcp_video());
626         _standard->Enable               (_generally_sensitive && _film && !_film->references_dcp_video() && !_film->references_dcp_audio());
627 }
628
629 void
630 DCPPanel::use_isdcf_name_toggled ()
631 {
632         if (!_film) {
633                 return;
634         }
635
636         _film->set_use_isdcf_name (_use_isdcf_name->GetValue ());
637 }
638
639 void
640 DCPPanel::edit_isdcf_button_clicked ()
641 {
642         if (!_film) {
643                 return;
644         }
645
646         ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, _film->isdcf_metadata (), _film->three_d ());
647         d->ShowModal ();
648         _film->set_isdcf_metadata (d->isdcf_metadata ());
649         d->Destroy ();
650 }
651
652 void
653 DCPPanel::setup_dcp_name ()
654 {
655         _dcp_name->SetLabel (std_to_wx (_film->dcp_name (true)));
656         _dcp_name->SetToolTip (std_to_wx (_film->dcp_name (true)));
657 }
658
659 void
660 DCPPanel::best_frame_rate_clicked ()
661 {
662         if (!_film) {
663                 return;
664         }
665
666         _film->set_video_frame_rate (_film->best_video_frame_rate ());
667 }
668
669 void
670 DCPPanel::three_d_changed ()
671 {
672         if (!_film) {
673                 return;
674         }
675
676         _film->set_three_d (_three_d->GetValue ());
677 }
678
679 void
680 DCPPanel::reencode_j2k_changed ()
681 {
682         if (!_film) {
683                 return;
684         }
685
686         _film->set_reencode_j2k (_reencode_j2k->GetValue());
687 }
688
689 void
690 DCPPanel::config_changed (Config::Property p)
691 {
692         _j2k_bandwidth->SetRange (1, Config::instance()->maximum_j2k_bandwidth() / 1000000);
693         setup_frame_rate_widget ();
694
695         if (p == Config::INTERFACE_COMPLEXITY) {
696                 _grid->Clear ();
697                 add_to_grid ();
698                 _sizer->Layout ();
699                 _grid->Layout ();
700
701                 _video_grid->Clear ();
702                 add_video_panel_to_grid ();
703                 _video_grid->Layout ();
704
705                 _audio_grid->Clear ();
706                 add_audio_panel_to_grid ();
707                 _audio_grid->Layout ();
708         }
709 }
710
711 void
712 DCPPanel::setup_frame_rate_widget ()
713 {
714         if (Config::instance()->allow_any_dcp_frame_rate ()) {
715                 _frame_rate_choice->Hide ();
716                 _frame_rate_spin->Show ();
717         } else {
718                 _frame_rate_choice->Show ();
719                 _frame_rate_spin->Hide ();
720         }
721
722         _frame_rate_sizer->Layout ();
723 }
724
725 wxPanel *
726 DCPPanel::make_video_panel ()
727 {
728         wxPanel* panel = new wxPanel (_notebook);
729         wxSizer* sizer = new wxBoxSizer (wxVERTICAL);
730         _video_grid = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
731         sizer->Add (_video_grid, 0, wxALL, 8);
732         panel->SetSizer (sizer);
733
734         _container_label = create_label (panel, _("Container"), true);
735         _container = new wxChoice (panel, wxID_ANY);
736         _container_size = new wxStaticText (panel, wxID_ANY, wxT (""));
737
738         _resolution_label = create_label (panel, _("Resolution"), true);
739         _resolution = new wxChoice (panel, wxID_ANY);
740
741         _frame_rate_label = create_label (panel, _("Frame Rate"), true);
742         _frame_rate_choice = new wxChoice (panel, wxID_ANY);
743         _frame_rate_sizer = new wxBoxSizer (wxHORIZONTAL);
744         _frame_rate_sizer->Add (_frame_rate_choice, 1, wxALIGN_CENTER_VERTICAL);
745         _frame_rate_spin = new wxSpinCtrl (panel, wxID_ANY);
746         _frame_rate_sizer->Add (_frame_rate_spin, 1, wxALIGN_CENTER_VERTICAL);
747         setup_frame_rate_widget ();
748         _best_frame_rate = new wxButton (panel, wxID_ANY, _("Use best"));
749         _frame_rate_sizer->Add (_best_frame_rate, 1, wxALIGN_CENTER_VERTICAL);
750
751         _three_d = new wxCheckBox (panel, wxID_ANY, _("3D"));
752
753         _j2k_bandwidth_label = create_label (panel, _("JPEG2000 bandwidth\nfor newly-encoded data"), true);
754         _j2k_bandwidth = new wxSpinCtrl (panel, wxID_ANY);
755         _mbits_label = create_label (panel, _("Mbit/s"), false);
756
757         _reencode_j2k = new wxCheckBox (panel, wxID_ANY, _("Re-encode JPEG2000 data from input"));
758
759         _container->Bind         (wxEVT_CHOICE,   boost::bind(&DCPPanel::container_changed, this));
760         _frame_rate_choice->Bind (wxEVT_CHOICE,   boost::bind(&DCPPanel::frame_rate_choice_changed, this));
761         _frame_rate_spin->Bind   (wxEVT_SPINCTRL, boost::bind(&DCPPanel::frame_rate_spin_changed, this));
762         _best_frame_rate->Bind   (wxEVT_BUTTON,   boost::bind(&DCPPanel::best_frame_rate_clicked, this));
763         _j2k_bandwidth->Bind     (wxEVT_SPINCTRL, boost::bind(&DCPPanel::j2k_bandwidth_changed, this));
764         /* Also listen to wxEVT_TEXT so that typing numbers directly in is always noticed */
765         _j2k_bandwidth->Bind     (wxEVT_TEXT,     boost::bind(&DCPPanel::j2k_bandwidth_changed, this));
766         _resolution->Bind        (wxEVT_CHOICE,   boost::bind(&DCPPanel::resolution_changed, this));
767         _three_d->Bind           (wxEVT_CHECKBOX, boost::bind(&DCPPanel::three_d_changed, this));
768         _reencode_j2k->Bind      (wxEVT_CHECKBOX, boost::bind(&DCPPanel::reencode_j2k_changed, this));
769
770         BOOST_FOREACH (Ratio const * i, Ratio::containers()) {
771                 _container->Append (std_to_wx(i->container_nickname()));
772         }
773
774         BOOST_FOREACH (int i, Config::instance()->allowed_dcp_frame_rates()) {
775                 _frame_rate_choice->Append (std_to_wx (boost::lexical_cast<string> (i)));
776         }
777
778         _j2k_bandwidth->SetRange (1, Config::instance()->maximum_j2k_bandwidth() / 1000000);
779         _frame_rate_spin->SetRange (1, 480);
780
781         _resolution->Append (_("2K"));
782         _resolution->Append (_("4K"));
783
784         add_video_panel_to_grid ();
785
786         return panel;
787 }
788
789 void
790 DCPPanel::add_video_panel_to_grid ()
791 {
792         bool const full = Config::instance()->interface_complexity() == Config::INTERFACE_FULL;
793
794         int r = 0;
795
796         add_label_to_sizer (_video_grid, _container_label, true, wxGBPosition (r, 0));
797         {
798                 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
799                 s->Add (_container, 1, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_X_GAP);
800                 s->Add (_container_size, 1, wxLEFT | wxALIGN_CENTER_VERTICAL);
801                 _video_grid->Add (s, wxGBPosition(r, 1));
802                 ++r;
803         }
804
805         add_label_to_sizer (_video_grid, _resolution_label, true, wxGBPosition (r, 0));
806         _video_grid->Add (_resolution, wxGBPosition (r, 1));
807         ++r;
808
809         add_label_to_sizer (_video_grid, _frame_rate_label, true, wxGBPosition (r, 0));
810         {
811                 _frame_rate_sizer = new wxBoxSizer (wxHORIZONTAL);
812                 _frame_rate_sizer->Add (_frame_rate_choice, 1, wxALIGN_CENTER_VERTICAL);
813                 _frame_rate_sizer->Add (_frame_rate_spin, 1, wxALIGN_CENTER_VERTICAL);
814                 _frame_rate_sizer->Add (_best_frame_rate, 1, wxALIGN_CENTER_VERTICAL);
815                 _video_grid->Add (_frame_rate_sizer, wxGBPosition (r, 1));
816                 ++r;
817         }
818
819         _video_grid->Add (_three_d, wxGBPosition (r, 0), wxGBSpan (1, 2));
820         ++r;
821
822         _j2k_bandwidth_label->Show (full);
823         _j2k_bandwidth->Show (full);
824         _mbits_label->Show (full);
825
826         if (full) {
827                 add_label_to_sizer (_video_grid, _j2k_bandwidth_label, true, wxGBPosition (r, 0));
828                 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
829                 s->Add (_j2k_bandwidth, 1);
830                 add_label_to_sizer (s, _mbits_label, false);
831                 _video_grid->Add (s, wxGBPosition (r, 1));
832                 ++r;
833                 _video_grid->Add (_reencode_j2k, wxGBPosition(r, 0), wxGBSpan(1, 2));
834         }
835 }
836
837 int
838 DCPPanel::minimum_allowed_audio_channels () const
839 {
840         int min = 2;
841         if (_film && _film->audio_processor ()) {
842                 min = _film->audio_processor()->out_channels ();
843         }
844
845         if (min % 2 == 1) {
846                 ++min;
847         }
848
849         return min;
850 }
851
852 wxPanel *
853 DCPPanel::make_audio_panel ()
854 {
855         wxPanel* panel = new wxPanel (_notebook);
856         wxSizer* sizer = new wxBoxSizer (wxVERTICAL);
857         _audio_grid = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
858         sizer->Add (_audio_grid, 0, wxALL, 8);
859         panel->SetSizer (sizer);
860
861         _channels_label = create_label (panel, _("Channels"), true);
862         _audio_channels = new wxChoice (panel, wxID_ANY);
863         setup_audio_channels_choice (_audio_channels, minimum_allowed_audio_channels ());
864
865         _processor_label = create_label (panel, _("Processor"), true);
866         _audio_processor = new wxChoice (panel, wxID_ANY);
867         _audio_processor->Append (_("None"), new wxStringClientData (N_("none")));
868         BOOST_FOREACH (AudioProcessor const * ap, AudioProcessor::all ()) {
869                 _audio_processor->Append (std_to_wx (ap->name ()), new wxStringClientData (std_to_wx (ap->id ())));
870         }
871
872         _show_audio = new wxButton (panel, wxID_ANY, _("Show audio..."));
873
874         _audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DCPPanel::audio_channels_changed, this));
875         _audio_processor->Bind (wxEVT_CHOICE, boost::bind (&DCPPanel::audio_processor_changed, this));
876         _show_audio->Bind (wxEVT_BUTTON, boost::bind (&DCPPanel::show_audio_clicked, this));
877
878         add_audio_panel_to_grid ();
879
880         return panel;
881 }
882
883 void
884 DCPPanel::add_audio_panel_to_grid ()
885 {
886         bool const full = Config::instance()->interface_complexity() == Config::INTERFACE_FULL;
887
888         int r = 0;
889
890         _channels_label->Show (full);
891         _audio_channels->Show (full);
892
893         if (full) {
894                 add_label_to_sizer (_audio_grid, _channels_label, true, wxGBPosition (r, 0));
895                 _audio_grid->Add (_audio_channels, wxGBPosition (r, 1));
896                 ++r;
897         }
898
899         _processor_label->Show (full);
900         _audio_processor->Show (full);
901
902         if (full) {
903                 add_label_to_sizer (_audio_grid, _processor_label, true, wxGBPosition (r, 0));
904                 _audio_grid->Add (_audio_processor, wxGBPosition (r, 1));
905                 ++r;
906         }
907
908         _audio_grid->Add (_show_audio, wxGBPosition (r, 0), wxGBSpan (1, 2));
909         ++r;
910 }
911
912 void
913 DCPPanel::copy_isdcf_name_button_clicked ()
914 {
915         _film->set_name (_film->isdcf_name (true));
916         _film->set_use_isdcf_name (false);
917 }
918
919 void
920 DCPPanel::audio_processor_changed ()
921 {
922         if (!_film) {
923                 return;
924         }
925
926         string const s = string_client_data (_audio_processor->GetClientObject (_audio_processor->GetSelection ()));
927         _film->set_audio_processor (AudioProcessor::from_id (s));
928 }
929
930 void
931 DCPPanel::show_audio_clicked ()
932 {
933         if (!_film) {
934                 return;
935         }
936
937         if (_audio_dialog) {
938                 _audio_dialog->Destroy ();
939                 _audio_dialog = 0;
940         }
941
942         AudioDialog* d = new AudioDialog (_panel, _film);
943         d->Show ();
944 }
945
946 void
947 DCPPanel::reel_type_changed ()
948 {
949         if (!_film) {
950                 return;
951         }
952
953         _film->set_reel_type (static_cast<ReelType> (_reel_type->GetSelection ()));
954 }
955
956 void
957 DCPPanel::reel_length_changed ()
958 {
959         if (!_film) {
960                 return;
961         }
962
963         _film->set_reel_length (_reel_length->GetValue() * 1000000000LL);
964 }