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