From d97029163865e212dc3d7b3c57c16459933a11f6 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 4 Sep 2020 17:24:12 +0200 Subject: [PATCH] Support CPL metadata. --- src/lib/copy_dcp_details_to_film.cc | 8 +- src/lib/film.cc | 139 +++++- src/lib/film.h | 68 ++- src/lib/util.cc | 1 + src/lib/writer.cc | 38 +- src/wx/content_version_dialog.cc | 53 +++ src/wx/content_version_dialog.h | 37 ++ src/wx/dcp_panel.cc | 38 +- src/wx/dcp_panel.h | 6 +- ...a_dialog.cc => interop_metadata_dialog.cc} | 23 +- ...ata_dialog.h => interop_metadata_dialog.h} | 4 +- src/wx/language_tag_dialog.cc | 408 ++++++++++++++++++ src/wx/language_tag_dialog.h | 81 ++++ src/wx/smpte_metadata_dialog.cc | 374 ++++++++++++++++ src/wx/smpte_metadata_dialog.h | 70 +++ src/wx/wscript | 5 +- test/import_dcp_test.cc | 4 +- 17 files changed, 1315 insertions(+), 42 deletions(-) create mode 100644 src/wx/content_version_dialog.cc create mode 100644 src/wx/content_version_dialog.h rename src/wx/{metadata_dialog.cc => interop_metadata_dialog.cc} (79%) rename src/wx/{metadata_dialog.h => interop_metadata_dialog.h} (91%) create mode 100644 src/wx/language_tag_dialog.cc create mode 100644 src/wx/language_tag_dialog.h create mode 100644 src/wx/smpte_metadata_dialog.cc create mode 100644 src/wx/smpte_metadata_dialog.h diff --git a/src/lib/copy_dcp_details_to_film.cc b/src/lib/copy_dcp_details_to_film.cc index a009735fb..d73ee8792 100644 --- a/src/lib/copy_dcp_details_to_film.cc +++ b/src/lib/copy_dcp_details_to_film.cc @@ -29,10 +29,13 @@ #include #include + using std::map; using std::string; +using std::vector; using boost::shared_ptr; + void copy_dcp_details_to_film (shared_ptr dcp, shared_ptr film) { @@ -67,7 +70,10 @@ copy_dcp_details_to_film (shared_ptr dcp, shared_ptr fil } film->set_ratings (dcp->ratings()); - film->set_content_version (dcp->content_version()); + + vector cv; + cv.push_back (dcp->content_version()); + film->set_content_versions (cv); } diff --git a/src/lib/film.cc b/src/lib/film.cc index 867944689..79ee20cfb 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -165,6 +165,11 @@ Film::Film (optional dir) , _user_explicit_video_frame_rate (false) , _user_explicit_container (false) , _user_explicit_resolution (false) + , _name_language (dcp::LanguageTag("en-US")) + , _release_territory (dcp::LanguageTag::RegionSubtag("US")) + , _version_number (1) + , _status (dcp::FINAL) + , _luminance (dcp::Luminance(4.5, dcp::Luminance::FOOT_LAMBERT)) , _state_version (current_state_version) , _dirty (false) , _tolerant (false) @@ -464,7 +469,18 @@ Film::metadata (bool with_content_paths) const BOOST_FOREACH (dcp::Rating i, _ratings) { i.as_xml (root->add_child("Rating")); } - root->add_child("ContentVersion")->add_child_text(_content_version); + BOOST_FOREACH (string i, _content_versions) { + root->add_child("ContentVersion")->add_child_text(i); + } + root->add_child("NameLanguage")->add_child_text(_name_language.to_string()); + root->add_child("ReleaseTerritory")->add_child_text(_release_territory.subtag()); + root->add_child("VersionNumber")->add_child_text(raw_convert(_version_number)); + root->add_child("Status")->add_child_text(dcp::status_to_string(_status)); + root->add_child("Chain")->add_child_text(_chain); + root->add_child("Distributor")->add_child_text(_distributor); + root->add_child("Facility")->add_child_text(_facility); + root->add_child("LuminanceValue")->add_child_text(raw_convert(_luminance.value())); + root->add_child("LuminanceUnit")->add_child_text(dcp::Luminance::unit_to_string(_luminance.unit())); root->add_child("UserExplicitContainer")->add_child_text(_user_explicit_container ? "1" : "0"); root->add_child("UserExplicitResolution")->add_child_text(_user_explicit_resolution ? "1" : "0"); _playlist->as_xml (root->add_child ("Playlist"), with_content_paths); @@ -612,7 +628,35 @@ Film::read_metadata (optional path) _ratings.push_back (dcp::Rating(i)); } - _content_version = f.optional_string_child("ContentVersion").get_value_or(""); + BOOST_FOREACH (cxml::ConstNodePtr i, f.node_children("ContentVersion")) { + _content_versions.push_back (i->content()); + } + + optional name_language = f.optional_string_child("NameLanguage"); + if (name_language) { + _name_language = dcp::LanguageTag (*name_language); + } + optional release_territory = f.optional_string_child("ReleaseTerritory"); + if (release_territory) { + _release_territory = dcp::LanguageTag::RegionSubtag (*release_territory); + } + + _version_number = f.optional_number_child("VersionNumber").get_value_or(0); + + optional status = f.optional_string_child("Status"); + if (status) { + _status = dcp::string_to_status (*status); + } + + _chain = f.optional_string_child("Chain").get_value_or(""); + _distributor = f.optional_string_child("Distributor").get_value_or(""); + _facility = f.optional_string_child("Facility").get_value_or(""); + + float value = f.optional_number_child("LuminanceValue").get_value_or(4.5); + optional unit = f.optional_string_child("LuminanceUnit"); + if (unit) { + _luminance = dcp::Luminance (value, dcp::Luminance::string_to_unit(*unit)); + } /* Disable guessing for files made in previous DCP-o-matic versions */ _user_explicit_container = f.optional_bool_child("UserExplicitContainer").get_value_or(true); @@ -1494,6 +1538,26 @@ Film::frame_size () const return fit_ratio_within (container()->ratio(), full_frame ()); } + +/** @return Area of Film::frame_size() that contains picture rather than pillar/letterboxing */ +dcp::Size +Film::active_area () const +{ + dcp::Size const frame = frame_size (); + dcp::Size active; + + BOOST_FOREACH (shared_ptr i, content()) { + if (i->video) { + dcp::Size s = i->video->scaled_size (frame); + active.width = max(active.width, s.width); + active.height = max(active.height, s.height); + } + } + + return active; +} + + /** @param recipient KDM recipient certificate. * @param trusted_devices Certificate thumbprints of other trusted devices (can be empty). * @param cpl_file CPL filename. @@ -1865,12 +1929,77 @@ Film::set_ratings (vector r) } void -Film::set_content_version (string v) +Film::set_content_versions (vector v) +{ + ChangeSignaller ch (this, CONTENT_VERSIONS); + _content_versions = v; +} + + +void +Film::set_name_language (dcp::LanguageTag lang) +{ + ChangeSignaller ch (this, NAME_LANGUAGE); + _name_language = lang; +} + + +void +Film::set_release_territory (dcp::LanguageTag::RegionSubtag region) { - ChangeSignaller ch (this, CONTENT_VERSION); - _content_version = v; + ChangeSignaller ch (this, RELEASE_TERRITORY); + _release_territory = region; } + +void +Film::set_status (dcp::Status s) +{ + ChangeSignaller ch (this, STATUS); + _status = s; +} + + +void +Film::set_version_number (int v) +{ + ChangeSignaller ch (this, VERSION_NUMBER); + _version_number = v; +} + + +void +Film::set_chain (string c) +{ + ChangeSignaller ch (this, CHAIN); + _chain = c; +} + + +void +Film::set_distributor (string d) +{ + ChangeSignaller ch (this, DISTRIBUTOR); + _distributor = d; +} + + +void +Film::set_luminance (dcp::Luminance l) +{ + ChangeSignaller ch (this, LUMINANCE); + _luminance = l; +} + + +void +Film::set_facility (string f) +{ + ChangeSignaller ch (this, FACILITY); + _facility = f; +} + + optional Film::marker (dcp::Marker type) const { diff --git a/src/lib/film.h b/src/lib/film.h index f5c20bccd..174805713 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -32,6 +32,7 @@ #include "frame_rate_change.h" #include "signaller.h" #include "dcp_text_track.h" +#include #include #include #include @@ -140,6 +141,7 @@ public: dcp::Size full_frame () const; dcp::Size frame_size () const; + dcp::Size active_area () const; std::vector cpls () const; @@ -229,7 +231,15 @@ public: REENCODE_J2K, MARKERS, RATINGS, - CONTENT_VERSION + CONTENT_VERSIONS, + NAME_LANGUAGE, + RELEASE_TERRITORY, + VERSION_NUMBER, + STATUS, + CHAIN, + DISTRIBUTOR, + FACILITY, + LUMINANCE }; @@ -325,8 +335,40 @@ public: return _ratings; } - std::string content_version () const { - return _content_version; + std::vector content_versions () const { + return _content_versions; + } + + dcp::LanguageTag name_language () const { + return _name_language; + } + + dcp::LanguageTag::RegionSubtag release_territory () const { + return _release_territory; + } + + int version_number () const { + return _version_number; + } + + dcp::Status status () const { + return _status; + } + + std::string chain () const { + return _chain; + } + + std::string distributor () const { + return _distributor; + } + + std::string facility () const { + return _facility; + } + + dcp::Luminance luminance () const { + return _luminance; } /* SET */ @@ -360,7 +402,15 @@ public: void unset_marker (dcp::Marker type); void clear_markers (); void set_ratings (std::vector r); - void set_content_version (std::string v); + void set_content_versions (std::vector v); + void set_name_language (dcp::LanguageTag lang); + void set_release_territory (dcp::LanguageTag::RegionSubtag region); + void set_version_number (int v); + void set_status (dcp::Status s); + void set_chain (std::string c); + void set_facility (std::string f); + void set_distributor (std::string d); + void set_luminance (dcp::Luminance l); /** Emitted when some property has of the Film is about to change or has changed */ mutable boost::signals2::signal Change; @@ -454,7 +504,15 @@ private: bool _user_explicit_resolution; std::map _markers; std::vector _ratings; - std::string _content_version; + std::vector _content_versions; + dcp::LanguageTag _name_language; + dcp::LanguageTag::RegionSubtag _release_territory; + int _version_number; + dcp::Status _status; + std::string _chain; + std::string _distributor; + std::string _facility; + dcp::Luminance _luminance; int _state_version; diff --git a/src/lib/util.cc b/src/lib/util.cc index 7824e7fed..32deac2e8 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -833,6 +833,7 @@ audio_channel_types (list mapped, int channels) break; case dcp::HI: case dcp::VI: + case dcp::MOTION_DATA: case dcp::SYNC_SIGNAL: case dcp::SIGN_LANGUAGE: case dcp::UNUSED: diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 8cfd712a0..0b1d8e06d 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -562,12 +562,14 @@ Writer::finish () pool.join_all (); service.stop (); - /* Add reels to CPL */ + /* Add reels */ BOOST_FOREACH (ReelWriter& i, _reels) { cpl->add (i.create_reel (_reel_assets, _fonts)); } + /* Add metadata */ + string creator = Config::instance()->dcp_creator(); if (creator.empty()) { creator = String::compose("DCP-o-matic %1 %2", dcpomatic_version, dcpomatic_git_commit); @@ -580,11 +582,39 @@ Writer::finish () cpl->set_ratings (_film->ratings()); - dcp::ContentVersion cv = cpl->content_version (); - cv.label_text = _film->content_version(); - cpl->set_content_version (cv); + vector cv; + BOOST_FOREACH (string i, _film->content_versions()) { + cv.push_back (dcp::ContentVersion(i)); + } + cpl->set_content_versions (cv); cpl->set_full_content_title_text (_film->name()); + cpl->set_full_content_title_text_language (_film->name_language()); + cpl->set_release_territory (_film->release_territory()); + cpl->set_version_number (_film->version_number()); + cpl->set_status (_film->status()); + cpl->set_chain (_film->chain()); + cpl->set_distributor (_film->distributor()); + cpl->set_facility (_film->facility()); + cpl->set_luminance (_film->luminance()); + + list ac = _film->mapped_audio_channels (); + dcp::MainSoundConfiguration::Field field = ( + find(ac.begin(), ac.end(), static_cast(dcp::BSL)) != ac.end() || + find(ac.begin(), ac.end(), static_cast(dcp::BSR)) != ac.end() + ) ? dcp::MainSoundConfiguration::SEVEN_POINT_ONE : dcp::MainSoundConfiguration::FIVE_POINT_ONE; + + dcp::MainSoundConfiguration msc (field, _film->audio_channels()); + BOOST_FOREACH (int i, ac) { + if (i < _film->audio_channels()) { + msc.set_mapping (i, static_cast(i)); + } + } + + cpl->set_main_sound_configuration (msc.to_string()); + cpl->set_main_sound_sample_rate (_film->audio_frame_rate()); + cpl->set_main_picture_stored_area (_film->frame_size()); + cpl->set_main_picture_active_area (_film->active_area()); shared_ptr signer; signer = Config::instance()->signer_chain (); diff --git a/src/wx/content_version_dialog.cc b/src/wx/content_version_dialog.cc new file mode 100644 index 000000000..37c9cd416 --- /dev/null +++ b/src/wx/content_version_dialog.cc @@ -0,0 +1,53 @@ +/* + Copyright (C) 2019 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#include "content_version_dialog.h" +#include "wx_util.h" + + +using std::string; + + +ContentVersionDialog::ContentVersionDialog (wxWindow* parent) + : TableDialog (parent, _("Content version"), 2, 1, true) +{ + add (_("Content version"), true); + _version= new wxTextCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(300, -1)); + add (_version); + + layout (); + + _version->SetFocus (); +} + + +void +ContentVersionDialog::set (string r) +{ + _version->SetValue (std_to_wx(r)); +} + + +string +ContentVersionDialog::get () const +{ + return wx_to_std(_version->GetValue()); +} diff --git a/src/wx/content_version_dialog.h b/src/wx/content_version_dialog.h new file mode 100644 index 000000000..8f375984d --- /dev/null +++ b/src/wx/content_version_dialog.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2020 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#include "table_dialog.h" +#include +#include + + +class ContentVersionDialog : public TableDialog +{ +public: + ContentVersionDialog (wxWindow* parent); + + void set (std::string); + std::string get () const; + +private: + wxTextCtrl* _version; +}; diff --git a/src/wx/dcp_panel.cc b/src/wx/dcp_panel.cc index 5046c5104..4e023db32 100644 --- a/src/wx/dcp_panel.cc +++ b/src/wx/dcp_panel.cc @@ -28,7 +28,8 @@ #include "check_box.h" #include "dcpomatic_button.h" #include "markers_dialog.h" -#include "metadata_dialog.h" +#include "interop_metadata_dialog.h" +#include "smpte_metadata_dialog.h" #include "lib/ratio.h" #include "lib/config.h" #include "lib/dcp_content_type.h" @@ -67,7 +68,8 @@ using dcp::locale_convert; DCPPanel::DCPPanel (wxNotebook* n, shared_ptr film, weak_ptr viewer) : _audio_dialog (0) , _markers_dialog (0) - , _metadata_dialog (0) + , _interop_metadata_dialog (0) + , _smpte_metadata_dialog (0) , _film (film) , _viewer (viewer) , _generally_sensitive (true) @@ -338,13 +340,23 @@ DCPPanel::markers_clicked () void DCPPanel::metadata_clicked () { - if (_metadata_dialog) { - _metadata_dialog->Destroy (); - _metadata_dialog = 0; - } + if (_film->interop()) { + if (_interop_metadata_dialog) { + _interop_metadata_dialog->Destroy (); + _interop_metadata_dialog = 0; + } - _metadata_dialog = new MetadataDialog (_panel, _film); - _metadata_dialog->Show (); + _interop_metadata_dialog = new InteropMetadataDialog (_panel, _film); + _interop_metadata_dialog->Show (); + } else { + if (_smpte_metadata_dialog) { + _smpte_metadata_dialog->Destroy (); + _smpte_metadata_dialog = 0; + } + + _smpte_metadata_dialog = new SMPTEMetadataDialog (_panel, _film); + _smpte_metadata_dialog->Show (); + } } void @@ -542,9 +554,13 @@ DCPPanel::set_film (shared_ptr film) _markers_dialog->Destroy (); _markers_dialog = 0; } - if (_metadata_dialog) { - _metadata_dialog->Destroy (); - _metadata_dialog = 0; + if (_interop_metadata_dialog) { + _interop_metadata_dialog->Destroy (); + _interop_metadata_dialog = 0; + } + if (_smpte_metadata_dialog) { + _smpte_metadata_dialog->Destroy (); + _smpte_metadata_dialog = 0; } _film = film; diff --git a/src/wx/dcp_panel.h b/src/wx/dcp_panel.h index 7a7d13897..465104c74 100644 --- a/src/wx/dcp_panel.h +++ b/src/wx/dcp_panel.h @@ -36,7 +36,8 @@ class wxGridBagSizer; class AudioDialog; class MarkersDialog; -class MetadataDialog; +class InteropMetadataDialog; +class SMPTEMetadataDialog; class Film; class FilmViewer; class Ratio; @@ -148,7 +149,8 @@ private: AudioDialog* _audio_dialog; MarkersDialog* _markers_dialog; - MetadataDialog* _metadata_dialog; + InteropMetadataDialog* _interop_metadata_dialog; + SMPTEMetadataDialog* _smpte_metadata_dialog; boost::shared_ptr _film; boost::weak_ptr _viewer; diff --git a/src/wx/metadata_dialog.cc b/src/wx/interop_metadata_dialog.cc similarity index 79% rename from src/wx/metadata_dialog.cc rename to src/wx/interop_metadata_dialog.cc index 2398ce2dc..f91bdcf7f 100644 --- a/src/wx/metadata_dialog.cc +++ b/src/wx/interop_metadata_dialog.cc @@ -18,7 +18,7 @@ */ -#include "metadata_dialog.h" +#include "interop_metadata_dialog.h" #include "editable_list.h" #include "rating_dialog.h" #include "lib/film.h" @@ -40,7 +40,7 @@ column (dcp::Rating r, int c) return r.label; } -MetadataDialog::MetadataDialog (wxWindow* parent, weak_ptr film) +InteropMetadataDialog::InteropMetadataDialog (wxWindow* parent, weak_ptr film) : wxDialog (parent, wxID_ANY, _("Metadata")) , _film (film) { @@ -65,8 +65,8 @@ MetadataDialog::MetadataDialog (wxWindow* parent, weak_ptr film) _ratings = new EditableList ( this, columns, - boost::bind(&MetadataDialog::ratings, this), - boost::bind(&MetadataDialog::set_ratings, this, _1), + boost::bind(&InteropMetadataDialog::ratings, this), + boost::bind(&InteropMetadataDialog::set_ratings, this, _1), boost::bind(&column, _1, _2), true, false @@ -79,7 +79,8 @@ MetadataDialog::MetadataDialog (wxWindow* parent, weak_ptr film) shared_ptr f = _film.lock(); DCPOMATIC_ASSERT (f); - _content_version->SetValue (std_to_wx(f->content_version())); + vector cv = f->content_versions(); + _content_version->SetValue (std_to_wx(cv.empty() ? "" : cv[0])); overall_sizer->Add (sizer, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); @@ -91,12 +92,12 @@ MetadataDialog::MetadataDialog (wxWindow* parent, weak_ptr film) overall_sizer->Layout (); overall_sizer->SetSizeHints (this); - _content_version->Bind (wxEVT_TEXT, boost::bind(&MetadataDialog::content_version_changed, this)); + _content_version->Bind (wxEVT_TEXT, boost::bind(&InteropMetadataDialog::content_version_changed, this)); _content_version->SetFocus (); } vector -MetadataDialog::ratings () const +InteropMetadataDialog::ratings () const { shared_ptr film = _film.lock (); DCPOMATIC_ASSERT (film); @@ -104,7 +105,7 @@ MetadataDialog::ratings () const } void -MetadataDialog::set_ratings (vector r) +InteropMetadataDialog::set_ratings (vector r) { shared_ptr film = _film.lock (); DCPOMATIC_ASSERT (film); @@ -112,9 +113,11 @@ MetadataDialog::set_ratings (vector r) } void -MetadataDialog::content_version_changed () +InteropMetadataDialog::content_version_changed () { shared_ptr film = _film.lock (); DCPOMATIC_ASSERT (film); - film->set_content_version (wx_to_std(_content_version->GetValue())); + vector cv; + cv.push_back (wx_to_std(_content_version->GetValue())); + film->set_content_versions (cv); } diff --git a/src/wx/metadata_dialog.h b/src/wx/interop_metadata_dialog.h similarity index 91% rename from src/wx/metadata_dialog.h rename to src/wx/interop_metadata_dialog.h index 892aa89df..43d028eab 100644 --- a/src/wx/metadata_dialog.h +++ b/src/wx/interop_metadata_dialog.h @@ -28,10 +28,10 @@ class Film; class RatingDialog; -class MetadataDialog : public wxDialog +class InteropMetadataDialog : public wxDialog { public: - MetadataDialog (wxWindow* parent, boost::weak_ptr film); + InteropMetadataDialog (wxWindow* parent, boost::weak_ptr film); private: std::vector ratings () const; diff --git a/src/wx/language_tag_dialog.cc b/src/wx/language_tag_dialog.cc new file mode 100644 index 000000000..f4e54e94b --- /dev/null +++ b/src/wx/language_tag_dialog.cc @@ -0,0 +1,408 @@ +/* + Copyright (C) 2020 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#include "lib/dcpomatic_assert.h" +#include "language_tag_dialog.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using std::pair; +using std::string; +using std::vector; +using boost::optional; +using boost::shared_ptr; +using boost::weak_ptr; + + +class SubtagListCtrl : public wxListCtrl +{ +public: + SubtagListCtrl (wxWindow* parent) + : wxListCtrl (parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_NO_HEADER | wxLC_VIRTUAL) + { + AppendColumn ("", wxLIST_FORMAT_LEFT, 80); + AppendColumn ("", wxLIST_FORMAT_LEFT, 400); + } + + void set (dcp::LanguageTag::SubtagType type, string search, optional subtag = optional()) + { + _all_subtags = dcp::LanguageTag::get_all(type); + set_search (search); + if (subtag) { + vector::iterator i = find(_matching_subtags.begin(), _matching_subtags.end(), *subtag); + if (i != _matching_subtags.end()) { + long item = std::distance(_matching_subtags.begin(), i); + SetItemState (item, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + EnsureVisible (item); + } + } + } + + void set_search (string search) + { + if (search == "") { + _matching_subtags = _all_subtags; + } else { + _matching_subtags.clear (); + + boost::algorithm::to_lower(search); + BOOST_FOREACH (dcp::LanguageTag::SubtagData const& i, _all_subtags) { + if ( + (boost::algorithm::to_lower_copy(i.subtag).find(search) != string::npos) || + (boost::algorithm::to_lower_copy(i.description).find(search) != string::npos)) { + _matching_subtags.push_back (i); + } + } + } + + SetItemCount (_matching_subtags.size()); + if (GetItemCount() > 0) { + RefreshItems (0, GetItemCount() - 1); + } + } + + optional selected_subtag () const + { + long int selected = GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (selected == -1) { + return optional(); + } + + DCPOMATIC_ASSERT (static_cast(selected) < _matching_subtags.size()); + return _matching_subtags[selected]; + } + +private: + wxString OnGetItemText (long item, long column) const + { + if (column == 0) { + return _matching_subtags[item].subtag; + } else { + return _matching_subtags[item].description; + } + } + + std::vector _all_subtags; + std::vector _matching_subtags; +}; + + +class LanguageSubtagPanel : public wxPanel +{ +public: + LanguageSubtagPanel (wxWindow* parent) + : wxPanel (parent, wxID_ANY) + { +#ifdef __WXGTK3__ + int const height = 30; +#else + int const height = -1; +#endif + + _search = new wxSearchCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200, height)); + _list = new SubtagListCtrl (this); + + wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL); + sizer->Add (_search, 0, wxALL, 8); + sizer->Add (_list, 1, wxALL, 8); + SetSizer (sizer); + + _search->Bind (wxEVT_TEXT, boost::bind(&LanguageSubtagPanel::search_changed, this)); + _list->Bind (wxEVT_LIST_ITEM_SELECTED, boost::bind(&LanguageSubtagPanel::selection_changed, this)); + _list->Bind (wxEVT_LIST_ITEM_DESELECTED, boost::bind(&LanguageSubtagPanel::selection_changed, this)); + } + + void set (dcp::LanguageTag::SubtagType type, string search, optional subtag = optional()) + { + _list->set (type, search, subtag); + _search->SetValue (wxString(search)); + } + + optional get () const + { + if (!_list->selected_subtag()) { + return optional(); + } + + return dcp::LanguageTag::RegionSubtag(_list->selected_subtag()->subtag); + } + + boost::signals2::signal)> SelectionChanged; + boost::signals2::signal SearchChanged; + +private: + void search_changed () + { + _list->set_search (_search->GetValue().ToStdString()); + SearchChanged (_search->GetValue().ToStdString()); + } + + void selection_changed () + { + SelectionChanged (_list->selected_subtag()); + } + + wxSearchCtrl* _search; + SubtagListCtrl* _list; +}; + + +LanguageTagDialog::LanguageTagDialog (wxWindow* parent, dcp::LanguageTag tag) + : wxDialog (parent, wxID_ANY, "Language Tag", wxDefaultPosition, wxSize(-1, 500)) +{ + _current_tag_list = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_NO_HEADER); + _current_tag_list->AppendColumn ("", wxLIST_FORMAT_LEFT, 200); + _current_tag_list->AppendColumn ("", wxLIST_FORMAT_LEFT, 400); + + wxBoxSizer* button_sizer = new wxBoxSizer (wxVERTICAL); + _add_script = new wxButton(this, wxID_ANY, "Add script"); + button_sizer->Add (_add_script, 0, wxTOP | wxBOTTOM | wxEXPAND, 2); + _add_region = new wxButton(this, wxID_ANY, "Add region"); + button_sizer->Add (_add_region, 0, wxTOP | wxBOTTOM | wxEXPAND, 2); + _add_variant = new wxButton(this, wxID_ANY, "Add variant"); + button_sizer->Add (_add_variant, 0, wxTOP | wxBOTTOM | wxEXPAND, 2); + _add_external = new wxButton(this, wxID_ANY, "Add external"); + button_sizer->Add (_add_external, 0, wxTOP | wxBOTTOM | wxEXPAND, 2); + + _choose_subtag_panel = new LanguageSubtagPanel (this); + _choose_subtag_panel->set (dcp::LanguageTag::LANGUAGE, ""); + + wxBoxSizer* ltor_sizer = new wxBoxSizer (wxHORIZONTAL); + ltor_sizer->Add (_current_tag_list, 1, wxALL, 8); + ltor_sizer->Add (button_sizer, 0, wxALL, 8); + ltor_sizer->Add (_choose_subtag_panel, 1, wxALL, 8); + + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + overall_sizer->Add (ltor_sizer, 0); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + SetSizerAndFit (overall_sizer); + + bool have_language = false; + vector > subtags = tag.subtags(); + for (vector >::const_iterator i = subtags.begin(); i != subtags.end(); ++i) { + add_to_current_tag (i->first, i->second); + if (i->first == dcp::LanguageTag::LANGUAGE) { + have_language = true; + } + } + + if (!have_language) { + add_to_current_tag (dcp::LanguageTag::LANGUAGE, dcp::LanguageTag::SubtagData("en", "English")); + } + + _add_script->Bind (wxEVT_BUTTON, boost::bind(&LanguageTagDialog::add_to_current_tag, this, dcp::LanguageTag::SCRIPT, boost::optional())); + _add_region->Bind (wxEVT_BUTTON, boost::bind(&LanguageTagDialog::add_to_current_tag, this, dcp::LanguageTag::REGION, boost::optional())); + _add_variant->Bind (wxEVT_BUTTON, boost::bind(&LanguageTagDialog::add_to_current_tag, this, dcp::LanguageTag::VARIANT, boost::optional())); + _add_external->Bind (wxEVT_BUTTON, boost::bind(&LanguageTagDialog::add_to_current_tag, this, dcp::LanguageTag::EXTLANG, boost::optional())); + _choose_subtag_panel->SelectionChanged.connect(bind(&LanguageTagDialog::chosen_subtag_changed, this, _1)); + _choose_subtag_panel->SearchChanged.connect(bind(&LanguageTagDialog::search_changed, this, _1)); + _current_tag_list->Bind (wxEVT_LIST_ITEM_SELECTED, boost::bind(&LanguageTagDialog::current_tag_selection_changed, this)); + _current_tag_list->Bind (wxEVT_LIST_ITEM_DESELECTED, boost::bind(&LanguageTagDialog::current_tag_selection_changed, this)); +} + + +dcp::LanguageTag LanguageTagDialog::get () const +{ + dcp::LanguageTag tag; + + vector variants; + vector extlangs; + + BOOST_FOREACH (Subtag i, _current_tag_subtags) { + if (!i.subtag) { + continue; + } + switch (i.type) { + case dcp::LanguageTag::LANGUAGE: + tag.set_language (i.subtag->subtag); + break; + case dcp::LanguageTag::SCRIPT: + tag.set_script (i.subtag->subtag); + break; + case dcp::LanguageTag::REGION: + tag.set_region (i.subtag->subtag); + break; + case dcp::LanguageTag::VARIANT: + variants.push_back (i.subtag->subtag); + break; + case dcp::LanguageTag::EXTLANG: + extlangs.push_back (i.subtag->subtag); + break; + } + } + + tag.set_variants (variants); + tag.set_extlangs (extlangs); + return tag; +} + + +string LanguageTagDialog::subtag_type_name (dcp::LanguageTag::SubtagType type) +{ + switch (type) { + case dcp::LanguageTag::LANGUAGE: + return "Language"; + case dcp::LanguageTag::SCRIPT: + return "Script"; + case dcp::LanguageTag::REGION: + return "Region"; + case dcp::LanguageTag::VARIANT: + return "Variant"; + case dcp::LanguageTag::EXTLANG: + return "External"; + } + + return ""; +} + + +void +LanguageTagDialog::search_changed (string search) +{ + long int selected = _current_tag_list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (selected >= 0) { + _current_tag_subtags[selected].last_search = search; + } +} + + +void +LanguageTagDialog::add_to_current_tag (dcp::LanguageTag::SubtagType type, optional subtag) +{ + _current_tag_subtags.push_back (Subtag(type, subtag)); + wxListItem it; + it.SetId (_current_tag_list->GetItemCount()); + it.SetColumn (0); + it.SetText (subtag_type_name(type)); + _current_tag_list->InsertItem (it); + it.SetColumn (1); + if (subtag) { + it.SetText (subtag->description); + } else { + it.SetText ("Select..."); + } + _current_tag_list->SetItem (it); + _current_tag_list->SetItemState (_current_tag_list->GetItemCount() - 1, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + _choose_subtag_panel->set (type, ""); + setup_sensitivity (); + current_tag_selection_changed (); +} + + +void +LanguageTagDialog::current_tag_selection_changed () +{ + long int selected = _current_tag_list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (selected >= 0) { + _choose_subtag_panel->Enable (true); + _choose_subtag_panel->set (_current_tag_subtags[selected].type, _current_tag_subtags[selected].last_search, _current_tag_subtags[selected].subtag); + } else { + _choose_subtag_panel->Enable (false); + } +} + + +void +LanguageTagDialog::chosen_subtag_changed (optional selection) +{ + if (!selection) { + return; + } + + long int selected = _current_tag_list->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (selected >= 0) { + _current_tag_subtags[selected].subtag = *selection; + _current_tag_list->SetItem (selected, 0, subtag_type_name(_current_tag_subtags[selected].type)); + _current_tag_list->SetItem (selected, 1, selection->description); + } +} + +void +LanguageTagDialog::setup_sensitivity () +{ + _add_script->Enable (); + _add_region->Enable (); + _add_variant->Enable (); + _add_external->Enable (); + BOOST_FOREACH (Subtag const& i, _current_tag_subtags) { + switch (i.type) { + case dcp::LanguageTag::SCRIPT: + _add_script->Enable (false); + break; + case dcp::LanguageTag::REGION: + _add_region->Enable (false); + break; + case dcp::LanguageTag::VARIANT: + _add_variant->Enable (false); + break; + case dcp::LanguageTag::EXTLANG: + _add_external->Enable (false); + break; + default: + break; + } + } +} + + +RegionSubtagDialog::RegionSubtagDialog (wxWindow* parent, dcp::LanguageTag::RegionSubtag region) + : wxDialog (parent, wxID_ANY, _("Region"), wxDefaultPosition, wxSize(-1, 500)) + , _panel (new LanguageSubtagPanel (this)) +{ + wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL); + sizer->Add (_panel, 1); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); + if (buttons) { + sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + SetSizer (sizer); + + _panel->set (dcp::LanguageTag::REGION, "", *dcp::LanguageTag::get_subtag_data(region)); +} + + +optional +RegionSubtagDialog::get () const +{ + return _panel->get (); +} + + diff --git a/src/wx/language_tag_dialog.h b/src/wx/language_tag_dialog.h new file mode 100644 index 000000000..3fc5251b8 --- /dev/null +++ b/src/wx/language_tag_dialog.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2020 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + + +#include +#include + + +class wxListCtrl; +class LanguageSubtagPanel; + + +class LanguageTagDialog : public wxDialog +{ +public: + class Subtag + { + public: + Subtag (dcp::LanguageTag::SubtagType type_, boost::optional subtag_) + : type (type_) + , subtag (subtag_) + {} + + dcp::LanguageTag::SubtagType type; + boost::optional subtag; + std::string last_search; + }; + + LanguageTagDialog (wxWindow* parent, dcp::LanguageTag tag); + + dcp::LanguageTag get () const; + + +private: + + std::string subtag_type_name (dcp::LanguageTag::SubtagType type); + void search_changed (std::string search); + void add_to_current_tag (dcp::LanguageTag::SubtagType type, boost::optional subtag); + void current_tag_selection_changed (); + void chosen_subtag_changed (boost::optional selection); + void setup_sensitivity (); + + std::vector _current_tag_subtags; + wxListCtrl* _current_tag_list; + LanguageSubtagPanel* _choose_subtag_panel; + wxButton* _add_script; + wxButton* _add_region; + wxButton* _add_variant; + wxButton* _add_external; +}; + + + +class RegionSubtagDialog : public wxDialog +{ +public: + RegionSubtagDialog (wxWindow* parent, dcp::LanguageTag::RegionSubtag region); + + boost::optional get () const; + +private: + LanguageSubtagPanel* _panel; +}; + diff --git a/src/wx/smpte_metadata_dialog.cc b/src/wx/smpte_metadata_dialog.cc new file mode 100644 index 000000000..6c130836f --- /dev/null +++ b/src/wx/smpte_metadata_dialog.cc @@ -0,0 +1,374 @@ +/* + Copyright (C) 2019-2020 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + +#include "content_version_dialog.h" +#include "editable_list.h" +#include "language_tag_dialog.h" +#include "smpte_metadata_dialog.h" +#include "rating_dialog.h" +#include "lib/film.h" +#include +#include +#include + +using std::string; +using std::vector; +using boost::optional; +using boost::shared_ptr; +using boost::weak_ptr; + + +static string +ratings_column (dcp::Rating r, int c) +{ + if (c == 0) { + return r.agency; + } + + return r.label; +} + + +static string +content_versions_column (string v, int) +{ + return v; +} + + +SMPTEMetadataDialog::SMPTEMetadataDialog (wxWindow* parent, weak_ptr weak_film) + : wxDialog (parent, wxID_ANY, _("Metadata")) + , _film (weak_film) +{ + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + SetSizer (overall_sizer); + + wxFlexGridSizer* sizer = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + sizer->AddGrowableCol (1, 1); + + wxButton* edit_name_language = 0; + Button* edit_release_territory = 0; + + add_label_to_sizer(sizer, this, _("Title language"), true); + { + wxSizer* s = new wxBoxSizer (wxHORIZONTAL); + _name_language = new wxStaticText (this, wxID_ANY, wxT("")); + _name_language->SetToolTip (wxString::Format(_("The language that the film's title (\"%s\") is in"), std_to_wx(film()->name()))); + s->Add (_name_language, 1, wxLEFT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP); + edit_name_language = new Button (this, _("Edit...")); + s->Add (edit_name_language, 0, wxLEFT, DCPOMATIC_SIZER_GAP); + sizer->Add (s, 0, wxEXPAND); + } + + add_label_to_sizer (sizer, this, _("Release territory"), true); + { + wxSizer* s = new wxBoxSizer (wxHORIZONTAL); + _release_territory = new wxStaticText (this, wxID_ANY, wxT("")); + s->Add (_release_territory, 1, wxLEFT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP); + edit_release_territory = new Button (this, _("Edit...")); + s->Add (edit_release_territory, 0, wxLEFT, DCPOMATIC_SIZER_GAP); + sizer->Add (s, 0, wxEXPAND); + } + + add_label_to_sizer (sizer, this, _("Version number"), true); + _version_number = new wxSpinCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 1000); + sizer->Add (_version_number, 0); + + add_label_to_sizer (sizer, this, _("Status"), true); + _status = new wxChoice (this, wxID_ANY); + sizer->Add (_status, 0); + + add_label_to_sizer (sizer, this, _("Chain"), true); + _chain = new wxTextCtrl (this, wxID_ANY); + sizer->Add (_chain, 1, wxEXPAND); + + add_label_to_sizer (sizer, this, _("Distributor"), true); + _distributor = new wxTextCtrl (this, wxID_ANY); + sizer->Add (_distributor, 1, wxEXPAND); + + add_label_to_sizer (sizer, this, _("Facility"), true); + _facility = new wxTextCtrl (this, wxID_ANY); + sizer->Add (_facility, 1, wxEXPAND); + + add_label_to_sizer (sizer, this, _("Luminance"), true); + { + wxSizer* s = new wxBoxSizer (wxHORIZONTAL); + _luminance_value = new wxSpinCtrlDouble (this, wxID_ANY); + _luminance_value->SetDigits (1); + _luminance_value->SetIncrement (0.1); + s->Add (_luminance_value, 0); + _luminance_unit = new wxChoice (this, wxID_ANY); + s->Add (_luminance_unit, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP); + sizer->Add (s, 1, wxEXPAND); + } + + { + int flags = wxALIGN_TOP | wxLEFT | wxRIGHT | wxTOP; +#ifdef __WXOSX__ + flags |= wxALIGN_RIGHT; +#endif + wxStaticText* m = create_label (this, _("Ratings"), true); + sizer->Add (m, 0, flags, DCPOMATIC_SIZER_GAP); + } + + vector columns; + columns.push_back (EditableListColumn("Agency", 200, true)); + columns.push_back (EditableListColumn("Label", 50, true)); + _ratings = new EditableList ( + this, + columns, + boost::bind(&SMPTEMetadataDialog::ratings, this), + boost::bind(&SMPTEMetadataDialog::set_ratings, this, _1), + boost::bind(&ratings_column, _1, _2), + true, + false + ); + sizer->Add (_ratings, 1, wxEXPAND); + + { + int flags = wxALIGN_TOP | wxLEFT | wxRIGHT | wxTOP; +#ifdef __WXOSX__ + flags |= wxALIGN_RIGHT; +#endif + wxStaticText* m = create_label (this, _("Content versions"), true); + sizer->Add (m, 0, flags, DCPOMATIC_SIZER_GAP); + } + + columns.clear (); + columns.push_back (EditableListColumn("Version", 350, true)); + _content_versions = new EditableList ( + this, + columns, + boost::bind(&SMPTEMetadataDialog::content_versions, this), + boost::bind(&SMPTEMetadataDialog::set_content_versions, this, _1), + boost::bind(&content_versions_column, _1, _2), + true, + false + ); + sizer->Add (_content_versions, 1, wxEXPAND); + + overall_sizer->Add (sizer, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxCLOSE); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + overall_sizer->Layout (); + overall_sizer->SetSizeHints (this); + + _status->Append (_("Temporary")); + _status->Append (_("Pre-release")); + _status->Append (_("Final")); + + _luminance_unit->Append (_("candela per m²")); + _luminance_unit->Append (_("foot lambert")); + + edit_name_language->Bind (wxEVT_BUTTON, boost::bind(&SMPTEMetadataDialog::edit_name_language, this)); + edit_release_territory->Bind (wxEVT_BUTTON, boost::bind(&SMPTEMetadataDialog::edit_release_territory, this)); + _version_number->Bind (wxEVT_SPINCTRL, boost::bind(&SMPTEMetadataDialog::version_number_changed, this)); + _status->Bind (wxEVT_CHOICE, boost::bind(&SMPTEMetadataDialog::status_changed, this)); + _chain->Bind (wxEVT_TEXT, boost::bind(&SMPTEMetadataDialog::chain_changed, this)); + _distributor->Bind (wxEVT_TEXT, boost::bind(&SMPTEMetadataDialog::distributor_changed, this)); + _facility->Bind (wxEVT_TEXT, boost::bind(&SMPTEMetadataDialog::facility_changed, this)); + _luminance_value->Bind (wxEVT_SPINCTRLDOUBLE, boost::bind(&SMPTEMetadataDialog::luminance_changed, this)); + _luminance_unit->Bind (wxEVT_CHOICE, boost::bind(&SMPTEMetadataDialog::luminance_changed, this)); + + _version_number->SetFocus (); + + _film_changed_connection = film()->Change.connect(boost::bind(&SMPTEMetadataDialog::film_changed, this, _1, _2)); + + film_changed (CHANGE_TYPE_DONE, Film::NAME_LANGUAGE); + film_changed (CHANGE_TYPE_DONE, Film::RELEASE_TERRITORY); + film_changed (CHANGE_TYPE_DONE, Film::VERSION_NUMBER); + film_changed (CHANGE_TYPE_DONE, Film::STATUS); + film_changed (CHANGE_TYPE_DONE, Film::CHAIN); + film_changed (CHANGE_TYPE_DONE, Film::DISTRIBUTOR); + film_changed (CHANGE_TYPE_DONE, Film::FACILITY); + film_changed (CHANGE_TYPE_DONE, Film::CONTENT_VERSIONS); + film_changed (CHANGE_TYPE_DONE, Film::LUMINANCE); +} + + +void +SMPTEMetadataDialog::film_changed (ChangeType type, Film::Property property) +{ + if (type != CHANGE_TYPE_DONE || film()->interop()) { + return; + } + + if (property == Film::NAME_LANGUAGE) { + checked_set (_name_language, std_to_wx(film()->name_language().to_string())); + } else if (property == Film::RELEASE_TERRITORY) { + checked_set (_release_territory, std_to_wx(*dcp::LanguageTag::get_subtag_description(dcp::LanguageTag::REGION, film()->release_territory().subtag()))); + } else if (property == Film::VERSION_NUMBER) { + checked_set (_version_number, film()->version_number()); + } else if (property == Film::STATUS) { + switch (film()->status()) { + case dcp::TEMP: + checked_set (_status, 0); + break; + case dcp::PRE: + checked_set (_status, 1); + break; + case dcp::FINAL: + checked_set (_status, 2); + break; + } + } else if (property == Film::CHAIN) { + checked_set (_chain, film()->chain()); + } else if (property == Film::DISTRIBUTOR) { + checked_set (_distributor, film()->distributor()); + } else if (property == Film::FACILITY) { + checked_set (_facility, film()->facility()); + } else if (property == Film::LUMINANCE) { + checked_set (_luminance_value, film()->luminance().value()); + switch (film()->luminance().unit()) { + case dcp::Luminance::CANDELA_PER_SQUARE_METRE: + checked_set (_luminance_unit, 0); + break; + case dcp::Luminance::FOOT_LAMBERT: + checked_set (_luminance_unit, 1); + break; + } + } +} + + +vector +SMPTEMetadataDialog::ratings () const +{ + return film()->ratings (); +} + + +void +SMPTEMetadataDialog::set_ratings (vector r) +{ + film()->set_ratings (r); +} + + +vector +SMPTEMetadataDialog::content_versions () const +{ + return film()->content_versions (); +} + + +void +SMPTEMetadataDialog::set_content_versions (vector cv) +{ + film()->set_content_versions (cv); +} + + +void +SMPTEMetadataDialog::edit_name_language () +{ + LanguageTagDialog* d = new LanguageTagDialog(this, film()->name_language()); + d->ShowModal (); + film()->set_name_language (d->get()); + d->Destroy (); +} + + +void +SMPTEMetadataDialog::edit_release_territory () +{ + RegionSubtagDialog* d = new RegionSubtagDialog(this, film()->release_territory()); + d->ShowModal (); + optional tag = d->get(); + if (tag) { + film()->set_release_territory (*tag); + } + d->Destroy (); +} + + +shared_ptr +SMPTEMetadataDialog::film () const +{ + shared_ptr film = _film.lock (); + DCPOMATIC_ASSERT (film); + return film; +} + + +void +SMPTEMetadataDialog::version_number_changed () +{ + film()->set_version_number (_version_number->GetValue()); +} + + +void +SMPTEMetadataDialog::status_changed () +{ + switch (_status->GetSelection()) { + case 0: + film()->set_status (dcp::TEMP); + break; + case 1: + film()->set_status (dcp::PRE); + break; + case 2: + film()->set_status (dcp::FINAL); + break; + } +} + + +void +SMPTEMetadataDialog::chain_changed () +{ + film()->set_chain (wx_to_std(_chain->GetValue())); +} + + +void +SMPTEMetadataDialog::distributor_changed () +{ + film()->set_distributor (wx_to_std(_distributor->GetValue())); +} + + +void +SMPTEMetadataDialog::facility_changed () +{ + film()->set_facility (wx_to_std(_facility->GetValue())); +} + + +void +SMPTEMetadataDialog::luminance_changed () +{ + dcp::Luminance::Unit unit; + switch (_luminance_unit->GetSelection()) { + case 0: + unit = dcp::Luminance::CANDELA_PER_SQUARE_METRE; + break; + case 1: + unit = dcp::Luminance::FOOT_LAMBERT; + break; + } + + film()->set_luminance (dcp::Luminance(_luminance_value->GetValue(), unit)); +} diff --git a/src/wx/smpte_metadata_dialog.h b/src/wx/smpte_metadata_dialog.h new file mode 100644 index 000000000..260d54de4 --- /dev/null +++ b/src/wx/smpte_metadata_dialog.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2019-2020 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DCP-o-matic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DCP-o-matic. If not, see . + +*/ + +#include "editable_list.h" +#include "lib/film.h" +#include +#include +#include +#include +#include + + +class Film; +class RatingDialog; +class ContentVersionDialog; + + +class SMPTEMetadataDialog : public wxDialog +{ +public: + SMPTEMetadataDialog (wxWindow* parent, boost::weak_ptr film); + +private: + std::vector ratings () const; + void set_ratings (std::vector r); + std::vector content_versions () const; + void set_content_versions (std::vector v); + void edit_name_language (); + void edit_release_territory (); + void version_number_changed (); + void status_changed (); + void chain_changed (); + void distributor_changed (); + void facility_changed (); + void luminance_changed (); + void film_changed (ChangeType type, Film::Property property); + boost::shared_ptr film () const; + + boost::weak_ptr _film; + wxStaticText* _name_language; + wxStaticText* _release_territory; + wxSpinCtrl* _version_number; + wxChoice* _status; + wxTextCtrl* _chain; + wxTextCtrl* _distributor; + wxTextCtrl* _facility; + wxSpinCtrlDouble* _luminance_value; + wxChoice* _luminance_unit; + EditableList* _ratings; + EditableList* _content_versions; + + boost::signals2::scoped_connection _film_changed_connection; +}; diff --git a/src/wx/wscript b/src/wx/wscript index e260667bc..d72c20940 100644 --- a/src/wx/wscript +++ b/src/wx/wscript @@ -46,6 +46,7 @@ sources = """ content_panel.cc content_properties_dialog.cc content_sub_panel.cc + content_version_dialog.cc content_view.cc controls.cc closed_captions_dialog.cc @@ -82,6 +83,7 @@ sources = """ html_dialog.cc initial_setup_dialog.cc instant_i18n_dialog.cc + interop_metadata_dialog.cc i18n_hook.cc job_view.cc job_view_dialog.cc @@ -91,10 +93,10 @@ sources = """ kdm_dialog.cc kdm_output_panel.cc kdm_timing_panel.cc + language_tag_dialog.cc make_chain_dialog.cc markers_dialog.cc message_dialog.cc - metadata_dialog.cc monitor_dialog.cc move_to_dialog.cc nag_dialog.cc @@ -128,6 +130,7 @@ sources = """ server_dialog.cc servers_list_dialog.cc simple_video_view.cc + smpte_metadata_dialog.cc standard_controls.cc static_text.cc subtitle_appearance_dialog.cc diff --git a/test/import_dcp_test.cc b/test/import_dcp_test.cc index 83dd0c6de..07116c1e2 100644 --- a/test/import_dcp_test.cc +++ b/test/import_dcp_test.cc @@ -170,7 +170,9 @@ BOOST_AUTO_TEST_CASE (import_dcp_metadata_test) ratings.push_back (dcp::Rating("MPAA", "NC-17")); film->set_ratings (ratings); - film->set_content_version ("Fred"); + vector cv; + cv.push_back ("Fred"); + film->set_content_versions (cv); film->make_dcp (); BOOST_REQUIRE (!wait_for_jobs()); -- 2.30.2