summaryrefslogtreecommitdiff
path: root/src/wx
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2022-03-01 22:41:56 +0100
committerCarl Hetherington <cth@carlh.net>2022-03-09 17:04:02 +0100
commit47d83b296248119d04b9226fd51a67e2fd3faac5 (patch)
treed9516f352dc28f1c42cc6e16247295611637ad42 /src/wx
parent161f7c27bd1aff63938a9512ab991de886691f97 (diff)
Improve ratings dialog to allow only valid values (#2199).
Diffstat (limited to 'src/wx')
-rw-r--r--src/wx/rating_dialog.cc302
-rw-r--r--src/wx/rating_dialog.h79
-rw-r--r--src/wx/wscript2
-rw-r--r--src/wx/wx_util.cc2
4 files changed, 363 insertions, 22 deletions
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.