diff options
| author | Carl Hetherington <cth@carlh.net> | 2022-03-01 22:41:56 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2022-03-09 17:04:02 +0100 |
| commit | 47d83b296248119d04b9226fd51a67e2fd3faac5 (patch) | |
| tree | d9516f352dc28f1c42cc6e16247295611637ad42 /src | |
| parent | 161f7c27bd1aff63938a9512ab991de886691f97 (diff) | |
Improve ratings dialog to allow only valid values (#2199).
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/cross.h | 3 | ||||
| -rw-r--r-- | src/lib/cross_linux.cc | 16 | ||||
| -rw-r--r-- | src/lib/cross_osx.cc | 11 | ||||
| -rw-r--r-- | src/lib/cross_windows.cc | 11 | ||||
| -rw-r--r-- | src/lib/dcp_content.h | 9 | ||||
| -rw-r--r-- | src/lib/dcp_examiner.h | 7 | ||||
| -rw-r--r-- | src/lib/film.h | 1 | ||||
| -rw-r--r-- | src/lib/util.cc | 2 | ||||
| -rw-r--r-- | src/lib/verify_dcp_job.cc | 2 | ||||
| -rw-r--r-- | src/wx/rating_dialog.cc | 302 | ||||
| -rw-r--r-- | src/wx/rating_dialog.h | 79 | ||||
| -rw-r--r-- | src/wx/wscript | 2 | ||||
| -rw-r--r-- | src/wx/wx_util.cc | 2 |
13 files changed, 387 insertions, 60 deletions
diff --git a/src/lib/cross.h b/src/lib/cross.h index aad223d60..99c6bc299 100644 --- a/src/lib/cross.h +++ b/src/lib/cross.h @@ -53,8 +53,7 @@ extern boost::filesystem::path disk_writer_path (); extern void maybe_open_console (); #endif extern boost::filesystem::path resources_path (); -extern boost::filesystem::path xsd_path (); -extern boost::filesystem::path tags_path (); +extern boost::filesystem::path libdcp_resources_path (); extern FILE * fopen_boost (boost::filesystem::path, std::string); extern int dcpomatic_fseek (FILE *, int64_t, int); extern void start_batch_converter (); diff --git a/src/lib/cross_linux.cc b/src/lib/cross_linux.cc index 07a70cc0b..14b8c71ba 100644 --- a/src/lib/cross_linux.cc +++ b/src/lib/cross_linux.cc @@ -109,22 +109,12 @@ resources_path () boost::filesystem::path -xsd_path () +libdcp_resources_path () { if (auto appdir = getenv("APPDIR")) { - return boost::filesystem::path(appdir) / "usr" / "share" / "libdcp" / "xsd"; + return boost::filesystem::path(appdir) / "usr" / "share" / "libdcp"; } - return boost::filesystem::canonical(LINUX_SHARE_PREFIX) / "libdcp" / "xsd"; -} - - -boost::filesystem::path -tags_path () -{ - if (auto appdir = getenv("APPDIR")) { - return boost::filesystem::path(appdir) / "usr" / "share" / "libdcp" / "tags"; - } - return boost::filesystem::canonical(LINUX_SHARE_PREFIX) / "libdcp" / "tags"; + return boost::filesystem::canonical(LINUX_SHARE_PREFIX) / "libdcp"; } diff --git a/src/lib/cross_osx.cc b/src/lib/cross_osx.cc index b06f45a77..b11ac90ef 100644 --- a/src/lib/cross_osx.cc +++ b/src/lib/cross_osx.cc @@ -115,16 +115,9 @@ resources_path () boost::filesystem::path -xsd_path () +libdcp_resources_path () { - return resources_path() / "xsd"; -} - - -boost::filesystem::path -tags_path () -{ - return resources_path() / "tags"; + return resources_path(); } diff --git a/src/lib/cross_windows.cc b/src/lib/cross_windows.cc index 4990f53ee..324b8cd8b 100644 --- a/src/lib/cross_windows.cc +++ b/src/lib/cross_windows.cc @@ -210,16 +210,9 @@ resources_path () boost::filesystem::path -xsd_path () +libdcp_resources_path () { - return directory_containing_executable().parent_path() / "xsd"; -} - - -boost::filesystem::path -tags_path () -{ - return directory_containing_executable().parent_path() / "tags"; + return resources_path (); } diff --git a/src/lib/dcp_content.h b/src/lib/dcp_content.h index 69520fbd6..40ed181fe 100644 --- a/src/lib/dcp_content.h +++ b/src/lib/dcp_content.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2018 Carl Hetherington <cth@carlh.net> + Copyright (C) 2014-2022 Carl Hetherington <cth@carlh.net> This file is part of DCP-o-matic. @@ -18,16 +18,21 @@ */ + #ifndef DCPOMATIC_DCP_CONTENT_H #define DCPOMATIC_DCP_CONTENT_H + /** @file src/lib/dcp_content.h * @brief DCPContent class. */ + #include "content.h" #include <libcxml/cxml.h> #include <dcp/encrypted_kdm.h> +#include <dcp/rating.h> + class DCPContentProperty { @@ -42,7 +47,6 @@ public: static int const CPL; }; -class ContentPart; /** @class DCPContent * @brief An existing DCP used as input. @@ -217,4 +221,5 @@ private: std::vector<std::string> _content_versions; }; + #endif diff --git a/src/lib/dcp_examiner.h b/src/lib/dcp_examiner.h index fd643a754..757e3ff03 100644 --- a/src/lib/dcp_examiner.h +++ b/src/lib/dcp_examiner.h @@ -18,19 +18,24 @@ */ + /** @file src/lib/dcp_examiner.h * @brief DCPExaminer class. */ -#include "video_examiner.h" + #include "audio_examiner.h" #include "dcp.h" #include "dcp_text_track.h" #include "dcpomatic_assert.h" +#include "video_examiner.h" #include <dcp/dcp_time.h> +#include <dcp/rating.h> + class DCPContent; + class DCPExaminer : public DCP, public VideoExaminer, public AudioExaminer { public: diff --git a/src/lib/film.h b/src/lib/film.h index 78a66e17f..a1bec3d53 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -36,6 +36,7 @@ #include <dcp/encrypted_kdm.h> #include <dcp/key.h> #include <dcp/language_tag.h> +#include <dcp/rating.h> #include <boost/filesystem.hpp> #include <boost/signals2.hpp> #include <boost/thread.hpp> diff --git a/src/lib/util.cc b/src/lib/util.cc index c165a5129..ccd505e57 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -399,7 +399,7 @@ DCPOMATIC_ENABLE_WARNINGS #endif Pango::init (); - dcp::init (tags_path()); + dcp::init (libdcp_resources_path()); #if defined(DCPOMATIC_WINDOWS) || defined(DCPOMATIC_OSX) /* Render something to fontconfig to create its cache */ diff --git a/src/lib/verify_dcp_job.cc b/src/lib/verify_dcp_job.cc index 1b30b2112..b59f5bfab 100644 --- a/src/lib/verify_dcp_job.cc +++ b/src/lib/verify_dcp_job.cc @@ -76,7 +76,7 @@ VerifyDCPJob::update_stage (string s, optional<boost::filesystem::path> path) void VerifyDCPJob::run () { - _notes = dcp::verify (_directories, bind (&VerifyDCPJob::update_stage, this, _1, _2), bind (&VerifyDCPJob::set_progress, this, _1, false), xsd_path()); + _notes = dcp::verify (_directories, bind (&VerifyDCPJob::update_stage, this, _1, _2), bind (&VerifyDCPJob::set_progress, this, _1, false), libdcp_resources_path() / "xsd"); bool failed = false; for (auto i: _notes) { diff --git a/src/wx/rating_dialog.cc b/src/wx/rating_dialog.cc index 6f574e83b..9886436a0 100644 --- a/src/wx/rating_dialog.cc +++ b/src/wx/rating_dialog.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2019 Carl Hetherington <cth@carlh.net> + Copyright (C) 2019-2022 Carl Hetherington <cth@carlh.net> This file is part of DCP-o-matic. @@ -18,34 +18,308 @@ */ + +#include "dcpomatic_spin_ctrl.h" #include "rating_dialog.h" #include "wx_util.h" +#include <unicode/unistr.h> +#include <wx/listctrl.h> +#include <wx/notebook.h> +#include <wx/srchctrl.h> + + +using std::string; +using std::vector; +using boost::optional; +#if BOOST_VERSION >= 106100 +using namespace boost::placeholders; +#endif + RatingDialog::RatingDialog (wxWindow* parent) - : TableDialog (parent, _("Ratings"), 2, 1, true) + : wxDialog (parent, wxID_ANY, _("Rating")) { - add (_("Agency"), true); - _agency = new wxTextCtrl (this, wxID_ANY); - add (_agency); + _notebook = new wxNotebook (this, wxID_ANY); + + _standard_page = new StandardRatingDialogPage (_notebook); + _custom_page = new CustomRatingDialogPage (_notebook); + + _notebook->AddPage (_standard_page, _("Standard")); + _notebook->AddPage (_custom_page, _("Custom")); + + _active_page = _standard_page; - add (_("Label"), true); - _label = new wxTextCtrl (this, wxID_ANY); - add (_label); + auto overall_sizer = new wxBoxSizer (wxVERTICAL); + overall_sizer->Add (_notebook, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); - layout (); + auto buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } - _agency->SetFocus (); + SetSizerAndFit (overall_sizer); + + _notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, boost::bind(&RatingDialog::page_changed, this)); + + _standard_page->Changed.connect(boost::bind(&RatingDialog::setup_sensitivity, this, _1)); + _custom_page->Changed.connect(boost::bind(&RatingDialog::setup_sensitivity, this, _1)); } + void -RatingDialog::set (dcp::Rating r) +RatingDialog::page_changed () { - _agency->SetValue (std_to_wx(r.agency)); - _label->SetValue (std_to_wx(r.label)); + if (_notebook->GetSelection() == 0) { + _active_page = _standard_page; + } else { + _active_page = _custom_page; + } } + +void +RatingDialog::set (dcp::Rating rating) +{ + if (_standard_page->set(rating)) { + _notebook->SetSelection(0); + } else { + _custom_page->set(rating); + _notebook->SetSelection(1); + } +} + + dcp::Rating RatingDialog::get () const { - return dcp::Rating(wx_to_std(_agency->GetValue()), wx_to_std(_label->GetValue())); + return _active_page->get(); +} + + +void +RatingDialog::setup_sensitivity (bool ok_valid) +{ + auto ok = dynamic_cast<wxButton *>(FindWindowById(wxID_OK, this)); + if (ok) { + ok->Enable (ok_valid); + } +} + + +RatingDialogPage::RatingDialogPage (wxNotebook* notebook) + : wxPanel (notebook, wxID_ANY) +{ + } + + +StandardRatingDialogPage::StandardRatingDialogPage (wxNotebook* notebook) + : RatingDialogPage (notebook) +{ + _search = new wxSearchCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200, search_ctrl_height())); +#ifndef __WXGTK3__ + /* The cancel button seems to be strangely broken in GTK3; clicking on it twice sometimes works */ + _search->ShowCancelButton (true); +#endif + + _found_systems_view = new wxListView (this, wxID_ANY, wxDefaultPosition, wxSize(600, 400), wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_NO_HEADER); + _found_systems_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 150); + _found_systems_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 50); + _found_systems_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 400); + _rating = new wxChoice (this, wxID_ANY); + + auto sizer = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + + add_label_to_sizer (sizer, this, _("Agency"), true, 0, wxALIGN_CENTER_VERTICAL); + sizer->Add (_search, 0, wxEXPAND, DCPOMATIC_SIZER_Y_GAP); + + sizer->AddSpacer (0); + sizer->Add (_found_systems_view, 1, wxEXPAND | wxBOTTOM, DCPOMATIC_SIZER_Y_GAP); + + add_label_to_sizer (sizer, this, _("Rating"), true, 0, wxALIGN_CENTER_VERTICAL); + sizer->Add (_rating, 1, wxEXPAND); + + auto pad_sizer = new wxBoxSizer (wxVERTICAL); + pad_sizer->Add (sizer, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + + SetSizerAndFit (pad_sizer); + + _search->Bind (wxEVT_TEXT, boost::bind(&StandardRatingDialogPage::search_changed, this)); + _found_systems_view->Bind (wxEVT_LIST_ITEM_SELECTED, boost::bind(&StandardRatingDialogPage::found_systems_view_selection_changed, this)); + _found_systems_view->Bind (wxEVT_LIST_ITEM_DESELECTED, boost::bind(&StandardRatingDialogPage::found_systems_view_selection_changed, this)); + + search_changed (); +} + + +/** The user clicked something different in the list of systems found by the search */ +void +StandardRatingDialogPage::found_systems_view_selection_changed () +{ + auto selected_index = _found_systems_view->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (selected_index < 0 || selected_index >= static_cast<int>(_found_systems.size())) { + _selected_system = boost::none; + } else { + _selected_system = _found_systems[selected_index]; + } + + /* Update the ratings dropdown */ + vector<wxString> items; + if (_selected_system) { + for (auto rating: _selected_system->ratings) { + items.push_back(std_to_wx(rating.label)); + } + } + + _rating->Set(items); + + if (!items.empty()) { + _rating->SetSelection(0); + } + + Changed (static_cast<bool>(_selected_system)); +} + + +void +StandardRatingDialogPage::search_changed () +{ + _found_systems_view->DeleteAllItems(); + _found_systems.clear(); + + icu::UnicodeString term(wx_to_std(_search->GetValue()).c_str(), "UTF-8"); + term = term.toLower(); + + int N = 0; + for (auto const& system: dcp::rating_systems()) { + icu::UnicodeString name(system.name.c_str(), "UTF-8"); + name = name.toLower(); + icu::UnicodeString country_and_region_names(system.country_and_region_names.c_str(), "UTF-8"); + country_and_region_names = country_and_region_names.toLower(); + icu::UnicodeString country_code(system.country_code.c_str(), "UTF-8"); + country_code = country_code.toLower(); + if (term.isEmpty() || name.indexOf(term) != -1 || country_and_region_names.indexOf(term) != -1 || country_code.indexOf(term) != -1) { + wxListItem item; + item.SetId(N); + _found_systems_view->InsertItem(item); + _found_systems_view->SetItem(N, 0, std_to_wx(system.name)); + _found_systems_view->SetItem(N, 1, std_to_wx(system.country_code)); + _found_systems_view->SetItem(N, 2, std_to_wx(system.country_and_region_names)); + _found_systems.push_back(system); + ++N; + } + } + + update_found_system_selection (); +} + + +/** Reflect _selected_system in the current _found_systems_view */ +void +StandardRatingDialogPage::update_found_system_selection () +{ + if (!_selected_system) { + for (auto i = 0; i < _found_systems_view->GetItemCount(); ++i) { + _found_systems_view->Select(i, false); + } + return; + } + + int index = 0; + for (auto const& system: _found_systems) { + bool const selected = system.agency == _selected_system->agency; + _found_systems_view->Select(index, selected); + if (selected) { + _found_systems_view->EnsureVisible(index); + } + ++index; + } +} + + +bool +StandardRatingDialogPage::set (dcp::Rating rating) +{ + _selected_system = boost::none; + for (auto const& system: dcp::rating_systems()) { + if (system.agency == rating.agency) { + _selected_system = system; + break; + } + } + + if (!_selected_system) { + return false; + } + + update_found_system_selection (); + + int rating_index = 0; + for (auto const& possible_rating: _selected_system->ratings) { + if (possible_rating.label == rating.label) { + _rating->SetSelection (rating_index); + return true; + } + ++rating_index; + } + + return false; +} + + +dcp::Rating +StandardRatingDialogPage::get () const +{ + DCPOMATIC_ASSERT (_selected_system); + auto selected_rating = _rating->GetSelection(); + DCPOMATIC_ASSERT (selected_rating >= 0); + DCPOMATIC_ASSERT (selected_rating < static_cast<int>(_selected_system->ratings.size())); + return dcp::Rating(_selected_system->agency, _selected_system->ratings[selected_rating].label); +} + + +CustomRatingDialogPage::CustomRatingDialogPage (wxNotebook* notebook) + : RatingDialogPage (notebook) +{ + auto sizer = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + + _agency = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)); + _rating = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1)); + + add_label_to_sizer (sizer, this, _("Agency"), true, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL); + sizer->Add (_agency, 1, wxEXPAND); + add_label_to_sizer (sizer, this, _("Rating"), true, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL); + sizer->Add (_rating, 1, wxEXPAND); + + auto pad_sizer = new wxBoxSizer (wxVERTICAL); + pad_sizer->Add (sizer, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); + + SetSizerAndFit (pad_sizer); + + _agency->Bind(wxEVT_TEXT, boost::bind(&CustomRatingDialogPage::changed, this)); + _rating->Bind(wxEVT_TEXT, boost::bind(&CustomRatingDialogPage::changed, this)); +} + + +void +CustomRatingDialogPage::changed () +{ + Changed (!_agency->IsEmpty() && !_rating->IsEmpty()); +} + + +dcp::Rating +CustomRatingDialogPage::get () const +{ + return dcp::Rating(wx_to_std(_agency->GetValue()), wx_to_std(_rating->GetValue())); +} + + +bool +CustomRatingDialogPage::set (dcp::Rating rating) +{ + _agency->SetValue(std_to_wx(rating.agency)); + _rating->SetValue(std_to_wx(rating.label)); + return true; +} + diff --git a/src/wx/rating_dialog.h b/src/wx/rating_dialog.h index 51869c0ab..27887baa2 100644 --- a/src/wx/rating_dialog.h +++ b/src/wx/rating_dialog.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2019 Carl Hetherington <cth@carlh.net> + Copyright (C) 2019-2022 Carl Hetherington <cth@carlh.net> This file is part of DCP-o-matic. @@ -18,10 +18,70 @@ */ -#include "table_dialog.h" -#include <dcp/types.h> -class RatingDialog : public TableDialog +#include <dcp/rating.h> +#include <wx/wx.h> +#include <boost/signals2.hpp> + + +class wxChoice; +class wxListView; +class wxNotebook; +class wxSearchCtrl; + + +class RatingDialogPage : public wxPanel +{ +public: + RatingDialogPage (wxNotebook* notebook); + virtual dcp::Rating get () const = 0; + virtual bool set (dcp::Rating rating) = 0; + + /** Emitted when the page has been changed, the parameter being true if OK + * should now be enabled in the main dialogue. + */ + boost::signals2::signal<void (bool)> Changed; +}; + + +class StandardRatingDialogPage : public RatingDialogPage +{ +public: + StandardRatingDialogPage (wxNotebook* notebook); + + dcp::Rating get () const override; + bool set (dcp::Rating rating) override; + +private: + void search_changed (); + void found_systems_view_selection_changed (); + void update_found_system_selection (); + + wxSearchCtrl* _search; + wxListView* _found_systems_view; + boost::optional<dcp::RatingSystem> _selected_system; + wxChoice* _rating; + std::vector<dcp::RatingSystem> _found_systems; +}; + + +class CustomRatingDialogPage : public RatingDialogPage +{ +public: + CustomRatingDialogPage (wxNotebook* notebook); + + dcp::Rating get () const override; + bool set (dcp::Rating rating) override; + +private: + void changed (); + + wxTextCtrl* _agency; + wxTextCtrl* _rating; +}; + + +class RatingDialog : public wxDialog { public: RatingDialog (wxWindow* parent); @@ -30,6 +90,13 @@ public: dcp::Rating get () const; private: - wxTextCtrl* _agency; - wxTextCtrl* _label; + void setup_sensitivity (bool ok_valid); + void page_changed (); + + wxNotebook* _notebook; + + StandardRatingDialogPage* _standard_page; + CustomRatingDialogPage* _custom_page; + RatingDialogPage* _active_page; }; + diff --git a/src/wx/wscript b/src/wx/wscript index 93afaeda2..7e028274e 100644 --- a/src/wx/wscript +++ b/src/wx/wscript @@ -309,7 +309,7 @@ def build(bld): obj.name = 'libdcpomatic2-wx' obj.export_includes = ['..'] - obj.uselib = 'BOOST_FILESYSTEM BOOST_THREAD BOOST_REGEX WXWIDGETS DCP SUB ZIP CXML RTAUDIO ' + obj.uselib = 'BOOST_FILESYSTEM BOOST_THREAD BOOST_REGEX WXWIDGETS DCP SUB ZIP CXML RTAUDIO ICU ' if bld.env.TARGET_LINUX: obj.uselib += 'GTK GL GLU ' if bld.env.TARGET_WINDOWS_64 or bld.env.TARGET_WINDOWS_32: diff --git a/src/wx/wx_util.cc b/src/wx/wx_util.cc index 988adeecc..fad3779bd 100644 --- a/src/wx/wx_util.cc +++ b/src/wx/wx_util.cc @@ -86,7 +86,7 @@ setup_osx_flags (wxSizer* s, bool left, int& flags) #endif -/** Add a wxStaticText to a wxSizer, aligning it at vertical centre. +/** Add a wxStaticText to a wxSizer. * @param s Sizer to add to. * @param p Parent window for the wxStaticText. * @param t Text for the wxStaticText. |
