2 Copyright (C) 2019-2022 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
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.
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.
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/>.
22 #include "dcpomatic_spin_ctrl.h"
23 #include "rating_dialog.h"
25 #include <dcp/warnings.h>
26 #include <unicode/unistr.h>
27 LIBDCP_DISABLE_WARNINGS
28 #include <wx/listctrl.h>
29 #include <wx/notebook.h>
30 #include <wx/srchctrl.h>
31 LIBDCP_ENABLE_WARNINGS
36 using boost::optional;
37 #if BOOST_VERSION >= 106100
38 using namespace boost::placeholders;
42 RatingDialog::RatingDialog (wxWindow* parent)
43 : wxDialog (parent, wxID_ANY, _("Rating"))
45 _notebook = new wxNotebook (this, wxID_ANY);
47 _standard_page = new StandardRatingDialogPage (_notebook);
48 _custom_page = new CustomRatingDialogPage (_notebook);
50 _notebook->AddPage (_standard_page, _("Standard"));
51 _notebook->AddPage (_custom_page, _("Custom"));
53 _active_page = _standard_page;
55 auto overall_sizer = new wxBoxSizer (wxVERTICAL);
56 overall_sizer->Add (_notebook, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
58 auto buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
60 overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
63 SetSizerAndFit (overall_sizer);
65 _notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, boost::bind(&RatingDialog::page_changed, this));
67 _standard_page->Changed.connect(boost::bind(&RatingDialog::setup_sensitivity, this, _1));
68 _custom_page->Changed.connect(boost::bind(&RatingDialog::setup_sensitivity, this, _1));
73 RatingDialog::page_changed ()
75 if (_notebook->GetSelection() == 0) {
76 _active_page = _standard_page;
78 _active_page = _custom_page;
84 RatingDialog::set (dcp::Rating rating)
86 if (_standard_page->set(rating)) {
87 _notebook->SetSelection(0);
89 _custom_page->set(rating);
90 _notebook->SetSelection(1);
96 RatingDialog::get () const
98 return _active_page->get();
103 RatingDialog::setup_sensitivity (bool ok_valid)
105 auto ok = dynamic_cast<wxButton *>(FindWindowById(wxID_OK, this));
107 ok->Enable (ok_valid);
112 RatingDialogPage::RatingDialogPage (wxNotebook* notebook)
113 : wxPanel (notebook, wxID_ANY)
119 StandardRatingDialogPage::StandardRatingDialogPage (wxNotebook* notebook)
120 : RatingDialogPage (notebook)
122 _search = new wxSearchCtrl (this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200, search_ctrl_height()));
124 /* The cancel button seems to be strangely broken in GTK3; clicking on it twice sometimes works */
125 _search->ShowCancelButton (true);
128 _found_systems_view = new wxListView (this, wxID_ANY, wxDefaultPosition, wxSize(600, 400), wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_NO_HEADER);
129 _found_systems_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 150);
130 _found_systems_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 50);
131 _found_systems_view->AppendColumn (wxT(""), wxLIST_FORMAT_LEFT, 400);
132 _rating = new wxChoice (this, wxID_ANY);
134 auto sizer = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
136 add_label_to_sizer (sizer, this, _("Agency"), true, 0, wxALIGN_CENTER_VERTICAL);
137 sizer->Add (_search, 0, wxEXPAND, DCPOMATIC_SIZER_Y_GAP);
139 sizer->AddSpacer (0);
140 sizer->Add (_found_systems_view, 1, wxEXPAND | wxBOTTOM, DCPOMATIC_SIZER_Y_GAP);
142 add_label_to_sizer (sizer, this, _("Rating"), true, 0, wxALIGN_CENTER_VERTICAL);
143 sizer->Add (_rating, 1, wxEXPAND);
145 auto pad_sizer = new wxBoxSizer (wxVERTICAL);
146 pad_sizer->Add (sizer, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
148 SetSizerAndFit (pad_sizer);
150 _search->Bind (wxEVT_TEXT, boost::bind(&StandardRatingDialogPage::search_changed, this));
151 _found_systems_view->Bind (wxEVT_LIST_ITEM_SELECTED, boost::bind(&StandardRatingDialogPage::found_systems_view_selection_changed, this));
152 _found_systems_view->Bind (wxEVT_LIST_ITEM_DESELECTED, boost::bind(&StandardRatingDialogPage::found_systems_view_selection_changed, this));
158 /** The user clicked something different in the list of systems found by the search */
160 StandardRatingDialogPage::found_systems_view_selection_changed ()
162 auto selected_index = _found_systems_view->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
163 if (selected_index < 0 || selected_index >= static_cast<int>(_found_systems.size())) {
164 _selected_system = boost::none;
166 _selected_system = _found_systems[selected_index];
169 /* Update the ratings dropdown */
171 if (_selected_system) {
172 for (auto rating: _selected_system->ratings) {
173 items.Add(std_to_wx(rating.label));
179 if (!items.empty()) {
180 _rating->SetSelection(0);
183 Changed (static_cast<bool>(_selected_system));
188 StandardRatingDialogPage::search_changed ()
190 _found_systems_view->DeleteAllItems();
191 _found_systems.clear();
193 icu::UnicodeString term(wx_to_std(_search->GetValue()).c_str(), "UTF-8");
194 term = term.toLower();
197 for (auto const& system: dcp::rating_systems()) {
198 icu::UnicodeString name(system.name.c_str(), "UTF-8");
199 name = name.toLower();
200 icu::UnicodeString country_and_region_names(system.country_and_region_names.c_str(), "UTF-8");
201 country_and_region_names = country_and_region_names.toLower();
202 icu::UnicodeString country_code(system.country_code.c_str(), "UTF-8");
203 country_code = country_code.toLower();
204 if (term.isEmpty() || name.indexOf(term) != -1 || country_and_region_names.indexOf(term) != -1 || country_code.indexOf(term) != -1) {
207 _found_systems_view->InsertItem(item);
208 _found_systems_view->SetItem(N, 0, std_to_wx(system.name));
209 _found_systems_view->SetItem(N, 1, std_to_wx(system.country_code));
210 _found_systems_view->SetItem(N, 2, std_to_wx(system.country_and_region_names));
211 _found_systems.push_back(system);
216 update_found_system_selection ();
220 /** Reflect _selected_system in the current _found_systems_view */
222 StandardRatingDialogPage::update_found_system_selection ()
224 if (!_selected_system) {
225 for (auto i = 0; i < _found_systems_view->GetItemCount(); ++i) {
226 _found_systems_view->Select(i, false);
232 for (auto const& system: _found_systems) {
233 bool const selected = system.agency == _selected_system->agency;
234 _found_systems_view->Select(index, selected);
236 _found_systems_view->EnsureVisible(index);
244 StandardRatingDialogPage::set (dcp::Rating rating)
246 _selected_system = boost::none;
247 for (auto const& system: dcp::rating_systems()) {
248 if (system.agency == rating.agency) {
249 _selected_system = system;
254 if (!_selected_system) {
258 update_found_system_selection ();
260 int rating_index = 0;
261 for (auto const& possible_rating: _selected_system->ratings) {
262 if (possible_rating.label == rating.label) {
263 _rating->SetSelection (rating_index);
274 StandardRatingDialogPage::get () const
276 DCPOMATIC_ASSERT (_selected_system);
277 auto selected_rating = _rating->GetSelection();
278 DCPOMATIC_ASSERT (selected_rating >= 0);
279 DCPOMATIC_ASSERT (selected_rating < static_cast<int>(_selected_system->ratings.size()));
280 return dcp::Rating(_selected_system->agency, _selected_system->ratings[selected_rating].label);
284 CustomRatingDialogPage::CustomRatingDialogPage (wxNotebook* notebook)
285 : RatingDialogPage (notebook)
287 auto sizer = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
289 _agency = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1));
290 _rating = new wxTextCtrl (this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(400, -1));
292 add_label_to_sizer (sizer, this, _("Agency"), true, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL);
293 sizer->Add (_agency, 1, wxEXPAND);
294 add_label_to_sizer (sizer, this, _("Rating"), true, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL);
295 sizer->Add (_rating, 1, wxEXPAND);
297 auto pad_sizer = new wxBoxSizer (wxVERTICAL);
298 pad_sizer->Add (sizer, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
300 SetSizerAndFit (pad_sizer);
302 _agency->Bind(wxEVT_TEXT, boost::bind(&CustomRatingDialogPage::changed, this));
303 _rating->Bind(wxEVT_TEXT, boost::bind(&CustomRatingDialogPage::changed, this));
308 CustomRatingDialogPage::changed ()
310 Changed (!_agency->IsEmpty() && !_rating->IsEmpty());
315 CustomRatingDialogPage::get () const
317 return dcp::Rating(wx_to_std(_agency->GetValue()), wx_to_std(_rating->GetValue()));
322 CustomRatingDialogPage::set (dcp::Rating rating)
324 _agency->SetValue(std_to_wx(rating.agency));
325 _rating->SetValue(std_to_wx(rating.label));