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