Add language to audio content and use it instead of the general metadata.
[dcpomatic.git] / src / wx / smpte_metadata_dialog.cc
1 /*
2     Copyright (C) 2019-2021 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_version_dialog.h"
23 #include "editable_list.h"
24 #include "language_tag_dialog.h"
25 #include "language_tag_widget.h"
26 #include "smpte_metadata_dialog.h"
27 #include "rating_dialog.h"
28 #include "lib/film.h"
29 #include <dcp/types.h>
30 #include <wx/gbsizer.h>
31 #include <wx/notebook.h>
32 #include <wx/spinctrl.h>
33
34
35 using std::string;
36 using std::vector;
37 using boost::optional;
38 using std::shared_ptr;
39 using std::weak_ptr;
40 #if BOOST_VERSION >= 106100
41 using namespace boost::placeholders;
42 #endif
43
44
45 static string
46 ratings_column (dcp::Rating r, int c)
47 {
48         if (c == 0) {
49                 return r.agency;
50         }
51
52         return r.label;
53 }
54
55
56 static string
57 content_versions_column (string v, int)
58 {
59         return v;
60 }
61
62
63 wxPanel *
64 SMPTEMetadataDialog::main_panel (wxWindow* parent)
65 {
66         auto panel = new wxPanel (parent, wxID_ANY);
67
68         auto sizer = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
69         sizer->AddGrowableCol (1, 1);
70
71         add_label_to_sizer (sizer, panel, _("Title language"), true, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL);
72         _name_language = new LanguageTagWidget(
73                 panel,
74                 wxString::Format(_("The language that the film's title (\"%s\") is in"), std_to_wx(film()->name())),
75                 film()->name_language()
76                 );
77         sizer->Add (_name_language->sizer(), 0, wxEXPAND);
78
79         {
80                 int flags = wxALIGN_TOP | wxRIGHT | wxTOP;
81 #ifdef __WXOSX__
82                 flags |= wxALIGN_RIGHT;
83 #endif
84                 auto m = create_label (panel, _("Ratings"), true);
85                 sizer->Add (m, 0, flags, DCPOMATIC_SIZER_GAP);
86         }
87
88         vector<EditableListColumn> columns;
89         columns.push_back (EditableListColumn("Agency", 200, true));
90         columns.push_back (EditableListColumn("Label", 50, true));
91         _ratings = new EditableList<dcp::Rating, RatingDialog> (
92                 panel,
93                 columns,
94                 boost::bind(&SMPTEMetadataDialog::ratings, this),
95                 boost::bind(&SMPTEMetadataDialog::set_ratings, this, _1),
96                 boost::bind(&ratings_column, _1, _2),
97                 true,
98                 false
99                 );
100         sizer->Add (_ratings, 1, wxEXPAND);
101
102         auto overall_sizer = new wxBoxSizer (wxVERTICAL);
103         overall_sizer->Add (sizer, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
104         panel->SetSizer (overall_sizer);
105
106         return panel;
107 }
108
109
110 wxPanel *
111 SMPTEMetadataDialog::advanced_panel (wxWindow* parent)
112 {
113         auto panel = new wxPanel (parent, wxID_ANY);
114
115         auto sizer = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
116         sizer->AddGrowableCol (1, 1);
117
118         _enable_release_territory = new wxCheckBox (panel, wxID_ANY, _("Release territory"));
119         sizer->Add (_enable_release_territory, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_GAP);
120         {
121                 auto s = new wxBoxSizer (wxHORIZONTAL);
122                 _release_territory_text = new wxStaticText (panel, wxID_ANY, wxT(""));
123                 s->Add (_release_territory_text, 1, wxLEFT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
124                 _edit_release_territory = new Button (panel, _("Edit..."));
125                 s->Add (_edit_release_territory, 0, wxLEFT, DCPOMATIC_SIZER_GAP);
126                 sizer->Add (s, 0, wxEXPAND);
127         }
128
129         add_label_to_sizer (sizer, panel, _("Version number"), true, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL);
130         _version_number = new wxSpinCtrl (panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 1000);
131         sizer->Add (_version_number, 0);
132
133         add_label_to_sizer (sizer, panel, _("Status"), true, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL);
134         _status = new wxChoice (panel, wxID_ANY);
135         sizer->Add (_status, 0);
136
137         _enable_chain = new wxCheckBox (panel, wxID_ANY, _("Chain"));
138         sizer->Add (_enable_chain, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL);
139         _chain = new wxTextCtrl (panel, wxID_ANY);
140         sizer->Add (_chain, 1, wxEXPAND);
141
142         _enable_distributor = new wxCheckBox (panel, wxID_ANY, _("Distributor"));
143         sizer->Add (_enable_distributor, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL);
144         _distributor = new wxTextCtrl (panel, wxID_ANY);
145         sizer->Add (_distributor, 1, wxEXPAND);
146
147         _enable_facility = new wxCheckBox (panel, wxID_ANY, _("Facility"));
148         sizer->Add (_enable_facility, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL);
149         _facility = new wxTextCtrl (panel, wxID_ANY);
150         sizer->Add (_facility, 1, wxEXPAND);
151
152         add_label_to_sizer (sizer, panel, _("Luminance"), true, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL);
153         {
154                 auto s = new wxBoxSizer (wxHORIZONTAL);
155                 _luminance_value = new wxSpinCtrlDouble (panel, wxID_ANY);
156                 _luminance_value->SetDigits (1);
157                 _luminance_value->SetIncrement (0.1);
158                 s->Add (_luminance_value, 0);
159                 _luminance_unit = new wxChoice (panel, wxID_ANY);
160                 s->Add (_luminance_unit, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
161                 sizer->Add (s, 1, wxEXPAND);
162         }
163
164         {
165                 int flags = wxALIGN_TOP | wxRIGHT | wxTOP;
166 #ifdef __WXOSX__
167                 flags |= wxALIGN_RIGHT;
168 #endif
169                 auto m = create_label (panel, _("Content versions"), true);
170                 sizer->Add (m, 0, flags, DCPOMATIC_SIZER_GAP);
171         }
172
173         vector<EditableListColumn> columns;
174         columns.push_back (EditableListColumn("Version", 350, true));
175         _content_versions = new EditableList<string, ContentVersionDialog> (
176                 panel,
177                 columns,
178                 boost::bind(&SMPTEMetadataDialog::content_versions, this),
179                 boost::bind(&SMPTEMetadataDialog::set_content_versions, this, _1),
180                 boost::bind(&content_versions_column, _1, _2),
181                 true,
182                 false
183                 );
184         sizer->Add (_content_versions, 1, wxEXPAND);
185
186         auto overall_sizer = new wxBoxSizer (wxVERTICAL);
187         overall_sizer->Add (sizer, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
188         panel->SetSizer (overall_sizer);
189
190         return panel;
191 }
192
193
194 SMPTEMetadataDialog::SMPTEMetadataDialog (wxWindow* parent, weak_ptr<Film> weak_film)
195         : wxDialog (parent, wxID_ANY, _("Metadata"))
196         , WeakFilm (weak_film)
197 {
198         auto notebook = new wxNotebook (this, wxID_ANY);
199         notebook->AddPage (main_panel(notebook), _("Standard"));
200         notebook->AddPage (advanced_panel(notebook), _("Advanced"));
201
202         auto overall_sizer = new wxBoxSizer (wxVERTICAL);
203         overall_sizer->Add (notebook, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
204
205         auto buttons = CreateSeparatedButtonSizer (wxCLOSE);
206         if (buttons) {
207                 overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
208         }
209
210         SetSizer (overall_sizer);
211         overall_sizer->Layout ();
212         overall_sizer->SetSizeHints (this);
213
214         _status->Append (_("Temporary"));
215         _status->Append (_("Pre-release"));
216         _status->Append (_("Final"));
217
218         _luminance_unit->Append (wxString::FromUTF8(_("candela per m²")));
219         _luminance_unit->Append (_("foot lambert"));
220
221         _name_language->Changed.connect (boost::bind(&SMPTEMetadataDialog::name_language_changed, this, _1));
222         _edit_release_territory->Bind (wxEVT_BUTTON, boost::bind(&SMPTEMetadataDialog::edit_release_territory, this));
223         _version_number->Bind (wxEVT_SPINCTRL, boost::bind(&SMPTEMetadataDialog::version_number_changed, this));
224         _status->Bind (wxEVT_CHOICE, boost::bind(&SMPTEMetadataDialog::status_changed, this));
225         _enable_chain->Bind (wxEVT_CHECKBOX, boost::bind(&SMPTEMetadataDialog::enable_chain_changed, this));
226         _chain->Bind (wxEVT_TEXT, boost::bind(&SMPTEMetadataDialog::chain_changed, this));
227         _enable_distributor->Bind (wxEVT_CHECKBOX, boost::bind(&SMPTEMetadataDialog::enable_distributor_changed, this));
228         _distributor->Bind (wxEVT_TEXT, boost::bind(&SMPTEMetadataDialog::distributor_changed, this));
229         _enable_facility->Bind (wxEVT_CHECKBOX, boost::bind(&SMPTEMetadataDialog::enable_facility_changed, this));
230         _facility->Bind (wxEVT_TEXT, boost::bind(&SMPTEMetadataDialog::facility_changed, this));
231         _luminance_value->Bind (wxEVT_SPINCTRLDOUBLE, boost::bind(&SMPTEMetadataDialog::luminance_changed, this));
232         _luminance_unit->Bind (wxEVT_CHOICE, boost::bind(&SMPTEMetadataDialog::luminance_changed, this));
233         _enable_release_territory->Bind (wxEVT_CHECKBOX, boost::bind(&SMPTEMetadataDialog::enable_release_territory_changed, this));
234
235         _version_number->SetFocus ();
236
237         _film_changed_connection = film()->Change.connect(boost::bind(&SMPTEMetadataDialog::film_changed, this, _1, _2));
238
239         film_changed (ChangeType::DONE, Film::Property::NAME_LANGUAGE);
240         film_changed (ChangeType::DONE, Film::Property::RELEASE_TERRITORY);
241         film_changed (ChangeType::DONE, Film::Property::VERSION_NUMBER);
242         film_changed (ChangeType::DONE, Film::Property::STATUS);
243         film_changed (ChangeType::DONE, Film::Property::CHAIN);
244         film_changed (ChangeType::DONE, Film::Property::DISTRIBUTOR);
245         film_changed (ChangeType::DONE, Film::Property::FACILITY);
246         film_changed (ChangeType::DONE, Film::Property::CONTENT_VERSIONS);
247         film_changed (ChangeType::DONE, Film::Property::LUMINANCE);
248
249         setup_sensitivity ();
250 }
251
252
253 void
254 SMPTEMetadataDialog::film_changed (ChangeType type, Film::Property property)
255 {
256         if (type != ChangeType::DONE || film()->interop()) {
257                 return;
258         }
259
260         if (property == Film::Property::NAME_LANGUAGE) {
261                 _name_language->set (film()->name_language());
262         } else if (property == Film::Property::RELEASE_TERRITORY) {
263                 auto rt = film()->release_territory();
264                 checked_set (_enable_release_territory, static_cast<bool>(rt));
265                 if (rt) {
266                         _release_territory = *rt;
267                         checked_set (_release_territory_text, std_to_wx(*dcp::LanguageTag::get_subtag_description(*_release_territory)));
268                 }
269         } else if (property == Film::Property::VERSION_NUMBER) {
270                 checked_set (_version_number, film()->version_number());
271         } else if (property == Film::Property::STATUS) {
272                 switch (film()->status()) {
273                 case dcp::Status::TEMP:
274                         checked_set (_status, 0);
275                         break;
276                 case dcp::Status::PRE:
277                         checked_set (_status, 1);
278                         break;
279                 case dcp::Status::FINAL:
280                         checked_set (_status, 2);
281                         break;
282                 }
283         } else if (property == Film::Property::CHAIN) {
284                 checked_set (_enable_chain, static_cast<bool>(film()->chain()));
285                 if (film()->chain()) {
286                         checked_set (_chain, *film()->chain());
287                 }
288         } else if (property == Film::Property::DISTRIBUTOR) {
289                 checked_set (_enable_distributor, static_cast<bool>(film()->distributor()));
290                 if (film()->distributor()) {
291                         checked_set (_distributor, *film()->distributor());
292                 }
293         } else if (property == Film::Property::FACILITY) {
294                 checked_set (_enable_facility, static_cast<bool>(film()->facility()));
295                 if (film()->facility()) {
296                         checked_set (_facility, *film()->facility());
297                 }
298         } else if (property == Film::Property::LUMINANCE) {
299                 auto lum = film()->luminance();
300                 if (lum) {
301                         checked_set (_luminance_value, lum->value());
302                         switch (lum->unit()) {
303                         case dcp::Luminance::Unit::CANDELA_PER_SQUARE_METRE:
304                                 checked_set (_luminance_unit, 0);
305                                 break;
306                         case dcp::Luminance::Unit::FOOT_LAMBERT:
307                                 checked_set (_luminance_unit, 1);
308                                 break;
309                         }
310                 } else {
311                         checked_set (_luminance_value, 4.5);
312                         checked_set (_luminance_unit, 1);
313                 }
314         }
315 }
316
317
318 vector<dcp::Rating>
319 SMPTEMetadataDialog::ratings () const
320 {
321         return film()->ratings ();
322 }
323
324
325 void
326 SMPTEMetadataDialog::set_ratings (vector<dcp::Rating> r)
327 {
328         film()->set_ratings (r);
329 }
330
331
332 vector<string>
333 SMPTEMetadataDialog::content_versions () const
334 {
335         return film()->content_versions ();
336 }
337
338
339 void
340 SMPTEMetadataDialog::set_content_versions (vector<string> cv)
341 {
342         film()->set_content_versions (cv);
343 }
344
345
346 void
347 SMPTEMetadataDialog::name_language_changed (dcp::LanguageTag tag)
348 {
349         film()->set_name_language (tag);
350 }
351
352
353 void
354 SMPTEMetadataDialog::edit_release_territory ()
355 {
356         DCPOMATIC_ASSERT (film()->release_territory());
357         auto d = new RegionSubtagDialog(this, *film()->release_territory());
358         d->ShowModal ();
359         auto tag = d->get();
360         if (tag) {
361                 _release_territory = *tag;
362                 film()->set_release_territory(*tag);
363         }
364         d->Destroy ();
365 }
366
367
368 void
369 SMPTEMetadataDialog::version_number_changed ()
370 {
371         film()->set_version_number (_version_number->GetValue());
372 }
373
374
375 void
376 SMPTEMetadataDialog::status_changed ()
377 {
378         switch (_status->GetSelection()) {
379         case 0:
380                 film()->set_status(dcp::Status::TEMP);
381                 break;
382         case 1:
383                 film()->set_status(dcp::Status::PRE);
384                 break;
385         case 2:
386                 film()->set_status(dcp::Status::FINAL);
387                 break;
388         }
389 }
390
391
392 void
393 SMPTEMetadataDialog::chain_changed ()
394 {
395         film()->set_chain (wx_to_std(_chain->GetValue()));
396 }
397
398
399 void
400 SMPTEMetadataDialog::distributor_changed ()
401 {
402         film()->set_distributor (wx_to_std(_distributor->GetValue()));
403 }
404
405
406 void
407 SMPTEMetadataDialog::facility_changed ()
408 {
409         film()->set_facility (wx_to_std(_facility->GetValue()));
410 }
411
412
413 void
414 SMPTEMetadataDialog::luminance_changed ()
415 {
416         dcp::Luminance::Unit unit;
417         switch (_luminance_unit->GetSelection()) {
418         case 0:
419                 unit = dcp::Luminance::Unit::CANDELA_PER_SQUARE_METRE;
420                 break;
421         case 1:
422                 unit = dcp::Luminance::Unit::FOOT_LAMBERT;
423                 break;
424         default:
425                 DCPOMATIC_ASSERT (false);
426         }
427
428         film()->set_luminance (dcp::Luminance(_luminance_value->GetValue(), unit));
429 }
430
431
432 void
433 SMPTEMetadataDialog::setup_sensitivity ()
434 {
435         {
436                 auto const enabled = _enable_release_territory->GetValue();
437                 _release_territory_text->Enable (enabled);
438                 _edit_release_territory->Enable (enabled);
439         }
440
441         _chain->Enable (_enable_chain->GetValue());
442         _distributor->Enable (_enable_distributor->GetValue());
443         _facility->Enable (_enable_facility->GetValue());
444 }
445
446
447 void
448 SMPTEMetadataDialog::enable_release_territory_changed ()
449 {
450         setup_sensitivity ();
451         if (_enable_release_territory->GetValue()) {
452                 film()->set_release_territory (_release_territory.get_value_or(dcp::LanguageTag::RegionSubtag("US")));
453         } else {
454                 film()->set_release_territory ();
455         }
456 }
457
458
459 void
460 SMPTEMetadataDialog::enable_chain_changed ()
461 {
462         setup_sensitivity ();
463         if (_enable_chain->GetValue()) {
464                 film()->set_chain (wx_to_std(_chain->GetValue()));
465         } else {
466                 film()->set_chain ();
467         }
468 }
469
470
471 void
472 SMPTEMetadataDialog::enable_distributor_changed ()
473 {
474         setup_sensitivity ();
475         if (_enable_distributor->GetValue()) {
476                 film()->set_distributor (wx_to_std(_distributor->GetValue()));
477         } else {
478                 film()->set_distributor ();
479         }
480 }
481
482
483 void
484 SMPTEMetadataDialog::enable_facility_changed ()
485 {
486         setup_sensitivity ();
487         if (_enable_facility->GetValue()) {
488                 film()->set_facility (wx_to_std(_facility->GetValue()));
489         } else {
490                 film()->set_facility ();
491         }
492 }
493
494