Add audio language configuration and pass it to libdcp.
[dcpomatic.git] / src / wx / smpte_metadata_dialog.cc
1 /*
2     Copyright (C) 2019-2020 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 #include "content_version_dialog.h"
22 #include "editable_list.h"
23 #include "language_tag_dialog.h"
24 #include "smpte_metadata_dialog.h"
25 #include "rating_dialog.h"
26 #include "lib/film.h"
27 #include <dcp/types.h>
28 #include <wx/gbsizer.h>
29 #include <wx/spinctrl.h>
30
31 using std::string;
32 using std::vector;
33 using boost::optional;
34 using boost::shared_ptr;
35 using boost::weak_ptr;
36
37
38 static string
39 ratings_column (dcp::Rating r, int c)
40 {
41         if (c == 0) {
42                 return r.agency;
43         }
44
45         return r.label;
46 }
47
48
49 static string
50 content_versions_column (string v, int)
51 {
52         return v;
53 }
54
55
56 SMPTEMetadataDialog::SMPTEMetadataDialog (wxWindow* parent, weak_ptr<Film> weak_film)
57         : wxDialog (parent, wxID_ANY, _("Metadata"))
58         , _film (weak_film)
59 {
60         wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
61         SetSizer (overall_sizer);
62
63         wxFlexGridSizer* sizer = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
64         sizer->AddGrowableCol (1, 1);
65
66         wxButton* edit_name_language = 0;
67         add_label_to_sizer(sizer, this, _("Title language"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
68         {
69                 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
70                 _name_language = new wxStaticText (this, wxID_ANY, wxT(""));
71                 _name_language->SetToolTip (wxString::Format(_("The language that the film's title (\"%s\") is in"), std_to_wx(film()->name())));
72                 s->Add (_name_language, 1, wxLEFT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
73                 edit_name_language = new Button (this, _("Edit..."));
74                 s->Add (edit_name_language, 0, wxLEFT, DCPOMATIC_SIZER_GAP);
75                 sizer->Add (s, 0, wxEXPAND);
76         }
77
78         wxButton* edit_audio_language = 0;
79         add_label_to_sizer(sizer, this, _("Audio language"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
80         {
81                 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
82                 _audio_language = new wxStaticText (this, wxID_ANY, wxT(""));
83                 _audio_language->SetToolTip (_("The main language that is spoken in the film's soundtrack"));
84                 s->Add (_audio_language, 1, wxLEFT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
85                 edit_audio_language = new Button (this, _("Edit..."));
86                 s->Add (edit_audio_language, 0, wxLEFT, DCPOMATIC_SIZER_GAP);
87                 sizer->Add (s, 0, wxEXPAND);
88         }
89
90         Button* edit_release_territory = 0;
91         add_label_to_sizer (sizer, this, _("Release territory"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
92         {
93                 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
94                 _release_territory = new wxStaticText (this, wxID_ANY, wxT(""));
95                 s->Add (_release_territory, 1, wxLEFT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
96                 edit_release_territory = new Button (this, _("Edit..."));
97                 s->Add (edit_release_territory, 0, wxLEFT, DCPOMATIC_SIZER_GAP);
98                 sizer->Add (s, 0, wxEXPAND);
99         }
100
101         add_label_to_sizer (sizer, this, _("Version number"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
102         _version_number = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 1000);
103         sizer->Add (_version_number, 0);
104
105         add_label_to_sizer (sizer, this, _("Status"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
106         _status = new wxChoice (this, wxID_ANY);
107         sizer->Add (_status, 0);
108
109         add_label_to_sizer (sizer, this, _("Chain"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
110         _chain = new wxTextCtrl (this, wxID_ANY);
111         sizer->Add (_chain, 1, wxEXPAND);
112
113         add_label_to_sizer (sizer, this, _("Distributor"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
114         _distributor = new wxTextCtrl (this, wxID_ANY);
115         sizer->Add (_distributor, 1, wxEXPAND);
116
117         add_label_to_sizer (sizer, this, _("Facility"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
118         _facility = new wxTextCtrl (this, wxID_ANY);
119         sizer->Add (_facility, 1, wxEXPAND);
120
121         add_label_to_sizer (sizer, this, _("Luminance"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
122         {
123                 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
124                 _luminance_value = new wxSpinCtrlDouble (this, wxID_ANY);
125                 _luminance_value->SetDigits (1);
126                 _luminance_value->SetIncrement (0.1);
127                 s->Add (_luminance_value, 0);
128                 _luminance_unit = new wxChoice (this, wxID_ANY);
129                 s->Add (_luminance_unit, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
130                 sizer->Add (s, 1, wxEXPAND);
131         }
132
133         {
134                 int flags = wxALIGN_TOP | wxLEFT | wxRIGHT | wxTOP;
135 #ifdef __WXOSX__
136                 flags |= wxALIGN_RIGHT;
137 #endif
138                 wxStaticText* m = create_label (this, _("Ratings"), true);
139                 sizer->Add (m, 0, flags, DCPOMATIC_SIZER_GAP);
140         }
141
142         vector<EditableListColumn> columns;
143         columns.push_back (EditableListColumn("Agency", 200, true));
144         columns.push_back (EditableListColumn("Label", 50, true));
145         _ratings = new EditableList<dcp::Rating, RatingDialog> (
146                 this,
147                 columns,
148                 boost::bind(&SMPTEMetadataDialog::ratings, this),
149                 boost::bind(&SMPTEMetadataDialog::set_ratings, this, _1),
150                 boost::bind(&ratings_column, _1, _2),
151                 true,
152                 false
153                 );
154         sizer->Add (_ratings, 1, wxEXPAND);
155
156         {
157                 int flags = wxALIGN_TOP | wxLEFT | wxRIGHT | wxTOP;
158 #ifdef __WXOSX__
159                 flags |= wxALIGN_RIGHT;
160 #endif
161                 wxStaticText* m = create_label (this, _("Content versions"), true);
162                 sizer->Add (m, 0, flags, DCPOMATIC_SIZER_GAP);
163         }
164
165         columns.clear ();
166         columns.push_back (EditableListColumn("Version", 350, true));
167         _content_versions = new EditableList<string, ContentVersionDialog> (
168                 this,
169                 columns,
170                 boost::bind(&SMPTEMetadataDialog::content_versions, this),
171                 boost::bind(&SMPTEMetadataDialog::set_content_versions, this, _1),
172                 boost::bind(&content_versions_column, _1, _2),
173                 true,
174                 false
175                 );
176         sizer->Add (_content_versions, 1, wxEXPAND);
177
178         overall_sizer->Add (sizer, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
179
180         wxSizer* buttons = CreateSeparatedButtonSizer (wxCLOSE);
181         if (buttons) {
182                 overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
183         }
184
185         overall_sizer->Layout ();
186         overall_sizer->SetSizeHints (this);
187
188         _status->Append (_("Temporary"));
189         _status->Append (_("Pre-release"));
190         _status->Append (_("Final"));
191
192         _luminance_unit->Append (_("candela per m²"));
193         _luminance_unit->Append (_("foot lambert"));
194
195         edit_name_language->Bind (wxEVT_BUTTON, boost::bind(&SMPTEMetadataDialog::edit_name_language, this));
196         edit_audio_language->Bind (wxEVT_BUTTON, boost::bind(&SMPTEMetadataDialog::edit_audio_language, this));
197         edit_release_territory->Bind (wxEVT_BUTTON, boost::bind(&SMPTEMetadataDialog::edit_release_territory, this));
198         _version_number->Bind (wxEVT_SPINCTRL, boost::bind(&SMPTEMetadataDialog::version_number_changed, this));
199         _status->Bind (wxEVT_CHOICE, boost::bind(&SMPTEMetadataDialog::status_changed, this));
200         _chain->Bind (wxEVT_TEXT, boost::bind(&SMPTEMetadataDialog::chain_changed, this));
201         _distributor->Bind (wxEVT_TEXT, boost::bind(&SMPTEMetadataDialog::distributor_changed, this));
202         _facility->Bind (wxEVT_TEXT, boost::bind(&SMPTEMetadataDialog::facility_changed, this));
203         _luminance_value->Bind (wxEVT_SPINCTRLDOUBLE, boost::bind(&SMPTEMetadataDialog::luminance_changed, this));
204         _luminance_unit->Bind (wxEVT_CHOICE, boost::bind(&SMPTEMetadataDialog::luminance_changed, this));
205
206         _version_number->SetFocus ();
207
208         _film_changed_connection = film()->Change.connect(boost::bind(&SMPTEMetadataDialog::film_changed, this, _1, _2));
209
210         film_changed (CHANGE_TYPE_DONE, Film::NAME_LANGUAGE);
211         film_changed (CHANGE_TYPE_DONE, Film::RELEASE_TERRITORY);
212         film_changed (CHANGE_TYPE_DONE, Film::VERSION_NUMBER);
213         film_changed (CHANGE_TYPE_DONE, Film::STATUS);
214         film_changed (CHANGE_TYPE_DONE, Film::CHAIN);
215         film_changed (CHANGE_TYPE_DONE, Film::DISTRIBUTOR);
216         film_changed (CHANGE_TYPE_DONE, Film::FACILITY);
217         film_changed (CHANGE_TYPE_DONE, Film::CONTENT_VERSIONS);
218         film_changed (CHANGE_TYPE_DONE, Film::LUMINANCE);
219 }
220
221
222 void
223 SMPTEMetadataDialog::film_changed (ChangeType type, Film::Property property)
224 {
225         if (type != CHANGE_TYPE_DONE || film()->interop()) {
226                 return;
227         }
228
229         if (property == Film::NAME_LANGUAGE) {
230                 checked_set (_name_language, std_to_wx(film()->name_language().to_string()));
231         } else if (property == Film::RELEASE_TERRITORY) {
232                 checked_set (_release_territory, std_to_wx(*dcp::LanguageTag::get_subtag_description(dcp::LanguageTag::REGION, film()->release_territory().subtag())));
233         } else if (property == Film::VERSION_NUMBER) {
234                 checked_set (_version_number, film()->version_number());
235         } else if (property == Film::STATUS) {
236                 switch (film()->status()) {
237                 case dcp::TEMP:
238                         checked_set (_status, 0);
239                         break;
240                 case dcp::PRE:
241                         checked_set (_status, 1);
242                         break;
243                 case dcp::FINAL:
244                         checked_set (_status, 2);
245                         break;
246                 }
247         } else if (property == Film::CHAIN) {
248                 checked_set (_chain, film()->chain());
249         } else if (property == Film::DISTRIBUTOR) {
250                 checked_set (_distributor, film()->distributor());
251         } else if (property == Film::FACILITY) {
252                 checked_set (_facility, film()->facility());
253         } else if (property == Film::LUMINANCE) {
254                 checked_set (_luminance_value, film()->luminance().value());
255                 switch (film()->luminance().unit()) {
256                 case dcp::Luminance::CANDELA_PER_SQUARE_METRE:
257                         checked_set (_luminance_unit, 0);
258                         break;
259                 case dcp::Luminance::FOOT_LAMBERT:
260                         checked_set (_luminance_unit, 1);
261                         break;
262                 }
263         }
264 }
265
266
267 vector<dcp::Rating>
268 SMPTEMetadataDialog::ratings () const
269 {
270         return film()->ratings ();
271 }
272
273
274 void
275 SMPTEMetadataDialog::set_ratings (vector<dcp::Rating> r)
276 {
277         film()->set_ratings (r);
278 }
279
280
281 vector<string>
282 SMPTEMetadataDialog::content_versions () const
283 {
284         return film()->content_versions ();
285 }
286
287
288 void
289 SMPTEMetadataDialog::set_content_versions (vector<string> cv)
290 {
291         film()->set_content_versions (cv);
292 }
293
294
295 void
296 SMPTEMetadataDialog::edit_name_language ()
297 {
298         LanguageTagDialog* d = new LanguageTagDialog(this, film()->name_language());
299         d->ShowModal ();
300         film()->set_name_language (d->get());
301         d->Destroy ();
302 }
303
304
305 void
306 SMPTEMetadataDialog::edit_audio_language ()
307 {
308         LanguageTagDialog* d = new LanguageTagDialog(this, film()->audio_language());
309         d->ShowModal ();
310         film()->set_audio_language (d->get());
311         d->Destroy ();
312 }
313
314
315 void
316 SMPTEMetadataDialog::edit_release_territory ()
317 {
318         RegionSubtagDialog* d = new RegionSubtagDialog(this, film()->release_territory());
319         d->ShowModal ();
320         optional<dcp::LanguageTag::RegionSubtag> tag = d->get();
321         if (tag) {
322                 film()->set_release_territory (*tag);
323         }
324         d->Destroy ();
325 }
326
327
328 shared_ptr<Film>
329 SMPTEMetadataDialog::film () const
330 {
331         shared_ptr<Film> film = _film.lock ();
332         DCPOMATIC_ASSERT (film);
333         return film;
334 }
335
336
337 void
338 SMPTEMetadataDialog::version_number_changed ()
339 {
340         film()->set_version_number (_version_number->GetValue());
341 }
342
343
344 void
345 SMPTEMetadataDialog::status_changed ()
346 {
347         switch (_status->GetSelection()) {
348         case 0:
349                 film()->set_status (dcp::TEMP);
350                 break;
351         case 1:
352                 film()->set_status (dcp::PRE);
353                 break;
354         case 2:
355                 film()->set_status (dcp::FINAL);
356                 break;
357         }
358 }
359
360
361 void
362 SMPTEMetadataDialog::chain_changed ()
363 {
364         film()->set_chain (wx_to_std(_chain->GetValue()));
365 }
366
367
368 void
369 SMPTEMetadataDialog::distributor_changed ()
370 {
371         film()->set_distributor (wx_to_std(_distributor->GetValue()));
372 }
373
374
375 void
376 SMPTEMetadataDialog::facility_changed ()
377 {
378         film()->set_facility (wx_to_std(_facility->GetValue()));
379 }
380
381
382 void
383 SMPTEMetadataDialog::luminance_changed ()
384 {
385         dcp::Luminance::Unit unit;
386         switch (_luminance_unit->GetSelection()) {
387         case 0:
388                 unit = dcp::Luminance::CANDELA_PER_SQUARE_METRE;
389                 break;
390         case 1:
391                 unit = dcp::Luminance::FOOT_LAMBERT;
392                 break;
393         }
394
395         film()->set_luminance (dcp::Luminance(_luminance_value->GetValue(), unit));
396 }