2 Copyright (C) 2012-2021 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 /** @file src/full_config_dialog.cc
23 * @brief A dialogue to edit all DCP-o-matic configuration.
27 #include "check_box.h"
28 #include "config_dialog.h"
29 #include "config_move_dialog.h"
30 #include "dcpomatic_button.h"
31 #include "dcpomatic_choice.h"
32 #include "dir_picker_ctrl.h"
33 #include "editable_list.h"
34 #include "email_dialog.h"
35 #include "file_picker_ctrl.h"
36 #include "filter_dialog.h"
37 #include "full_config_dialog.h"
38 #include "kdm_choice.h"
39 #include "language_tag_widget.h"
40 #include "make_chain_dialog.h"
41 #include "nag_dialog.h"
42 #include "name_format_editor.h"
43 #include "password_entry.h"
44 #include "region_subtag_widget.h"
45 #include "send_test_email_dialog.h"
46 #include "server_dialog.h"
47 #include "static_text.h"
49 #include "grok/gpu_config_panel.h"
52 #include "lib/config.h"
53 #include "lib/cross.h"
54 #include "lib/dcp_content_type.h"
55 #include "lib/email.h"
56 #include "lib/exceptions.h"
57 #include "lib/filter.h"
59 #include "lib/ratio.h"
61 #include <dcp/certificate_chain.h>
62 #include <dcp/exceptions.h>
63 #include <dcp/filesystem.h>
64 #include <dcp/locale_convert.h>
65 #include <dcp/warnings.h>
66 LIBDCP_DISABLE_WARNINGS
67 #include <wx/filepicker.h>
68 #include <wx/preferences.h>
69 #include <wx/spinctrl.h>
70 #include <wx/stdpaths.h>
71 LIBDCP_ENABLE_WARNINGS
73 #include <boost/filesystem.hpp>
83 using std::shared_ptr;
87 using boost::optional;
88 #if BOOST_VERSION >= 106100
89 using namespace boost::placeholders;
91 using dcp::locale_convert;
94 class FullGeneralPage : public GeneralPage
97 FullGeneralPage (wxSize panel_size, int border)
98 : GeneralPage (panel_size, border)
102 void setup () override
104 auto table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
105 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
108 add_language_controls (table, r);
110 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic should use"), true, wxGBPosition (r, 0));
111 _master_encoding_threads = new wxSpinCtrl (_panel);
112 table->Add (_master_encoding_threads, wxGBPosition (r, 1));
115 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic encode server should use"), true, wxGBPosition (r, 0));
116 _server_encoding_threads = new wxSpinCtrl (_panel);
117 table->Add (_server_encoding_threads, wxGBPosition (r, 1));
120 add_label_to_sizer (table, _panel, _("Configuration file"), true, wxGBPosition (r, 0));
121 _config_file = new FilePickerCtrl(_panel, _("Select configuration file"), "*.xml", true, false, "ConfigFilePath");
122 table->Add (_config_file, wxGBPosition (r, 1));
125 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
126 _cinemas_file = new FilePickerCtrl(_panel, _("Select cinema and screen database file"), "*.xml", true, false, "CinemaDatabasePath");
127 table->Add (_cinemas_file, wxGBPosition (r, 1));
128 auto export_cinemas = new Button (_panel, _("Export..."));
129 table->Add (export_cinemas, wxGBPosition (r, 2));
132 add_label_to_sizer(table, _panel, _("Default \"add file\" location"), true, wxGBPosition(r, 0));
133 _default_add_file_location = new Choice(_panel);
134 table->Add(_default_add_file_location, wxGBPosition(r, 1));
137 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
138 _analyse_ebur128 = new CheckBox (_panel, _("Find integrated loudness, true peak and loudness range when analysing audio"));
139 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
143 _automatic_audio_analysis = new CheckBox (_panel, _("Automatically analyse content audio"));
144 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
147 add_update_controls (table, r);
149 _default_add_file_location->add(_("Same place as last time"));
150 _default_add_file_location->add(_("Same place as project"));
151 _default_add_file_location->bind(&FullGeneralPage::default_add_file_location_changed, this);
153 _config_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::config_file_changed, this));
154 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::cinemas_file_changed, this));
156 _master_encoding_threads->SetRange (1, 128);
157 _master_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::master_encoding_threads_changed, this));
158 _server_encoding_threads->SetRange (1, 128);
159 _server_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::server_encoding_threads_changed, this));
160 export_cinemas->Bind (wxEVT_BUTTON, boost::bind (&FullGeneralPage::export_cinemas_file, this));
162 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
163 _analyse_ebur128->bind(&FullGeneralPage::analyse_ebur128_changed, this);
165 _automatic_audio_analysis->bind(&FullGeneralPage::automatic_audio_analysis_changed, this);
168 void config_changed () override
170 auto config = Config::instance ();
172 checked_set (_master_encoding_threads, config->master_encoding_threads ());
173 checked_set (_server_encoding_threads, config->server_encoding_threads ());
174 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
175 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
177 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
178 checked_set (_config_file, config->config_read_file());
179 checked_set (_cinemas_file, config->cinemas_file());
180 checked_set(_default_add_file_location, config->default_add_file_location() == Config::DefaultAddFileLocation::SAME_AS_LAST_TIME ? 0 : 1);
182 GeneralPage::config_changed ();
185 void export_cinemas_file ()
188 _panel, _("Select Cinemas File"), wxEmptyString, wxEmptyString, wxT("XML files (*.xml)|*.xml"),
189 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
192 if (dialog.ShowModal() == wxID_OK) {
193 dcp::filesystem::copy_file(Config::instance()->cinemas_file(), wx_to_std(dialog.GetPath()), boost::filesystem::copy_option::overwrite_if_exists);
197 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
198 void analyse_ebur128_changed ()
200 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue());
204 void automatic_audio_analysis_changed ()
206 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue());
209 void master_encoding_threads_changed ()
211 Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue());
214 void server_encoding_threads_changed ()
216 Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue());
219 void config_file_changed ()
221 auto config = Config::instance();
222 auto const new_file = _config_file->path();
223 if (!new_file || *new_file == config->config_read_file()) {
226 bool copy_and_link = true;
227 if (dcp::filesystem::exists(*new_file)) {
228 ConfigMoveDialog dialog(_panel, *new_file);
229 if (dialog.ShowModal() == wxID_OK) {
230 copy_and_link = false;
236 if (new_file != config->config_read_file()) {
237 config->copy_and_link(*new_file);
240 config->link(*new_file);
244 void cinemas_file_changed ()
246 if (auto path = _cinemas_file->path()) {
247 Config::instance()->set_cinemas_file(*path);
251 void default_add_file_location_changed()
253 Config::instance()->set_default_add_file_location(
254 _default_add_file_location->get().get_value_or(0) == 0 ? Config::DefaultAddFileLocation::SAME_AS_LAST_TIME : Config::DefaultAddFileLocation::SAME_AS_PROJECT
258 Choice* _default_add_file_location;
259 wxSpinCtrl* _master_encoding_threads;
260 wxSpinCtrl* _server_encoding_threads;
261 FilePickerCtrl* _config_file;
262 FilePickerCtrl* _cinemas_file;
263 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
264 CheckBox* _analyse_ebur128;
266 CheckBox* _automatic_audio_analysis;
270 class DefaultsPage : public Page
273 DefaultsPage (wxSize panel_size, int border)
274 : Page (panel_size, border)
277 wxString GetName () const override
279 return _("Defaults");
283 wxBitmap GetLargeIcon () const override
285 return wxBitmap(icon_path("defaults"), wxBITMAP_TYPE_PNG);
290 void setup () override
292 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
293 table->AddGrowableCol (1, 1);
294 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
297 add_label_to_sizer (table, _panel, _("Default duration of still images"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
298 auto s = new wxBoxSizer (wxHORIZONTAL);
299 _still_length = new wxSpinCtrl (_panel);
300 s->Add (_still_length);
301 add_label_to_sizer (s, _panel, _("s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
305 add_label_to_sizer (table, _panel, _("Default directory for new films"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
306 #ifdef DCPOMATIC_USE_OWN_PICKER
307 _directory = new DirPickerCtrl (_panel);
309 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
311 table->Add (_directory, 1, wxEXPAND);
313 add_label_to_sizer (table, _panel, _("Default content type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
314 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
315 table->Add (_dcp_content_type);
317 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
318 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
319 table->Add (_dcp_audio_channels);
322 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
323 auto s = new wxBoxSizer (wxHORIZONTAL);
324 _j2k_bandwidth = new wxSpinCtrl (_panel);
325 s->Add (_j2k_bandwidth);
326 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
331 add_label_to_sizer (table, _panel, _("Default audio delay"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
332 auto s = new wxBoxSizer (wxHORIZONTAL);
333 _audio_delay = new wxSpinCtrl (_panel);
334 s->Add (_audio_delay);
335 add_label_to_sizer (s, _panel, _("ms"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
339 add_label_to_sizer (table, _panel, _("Default standard"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
340 _standard = new wxChoice (_panel, wxID_ANY);
341 table->Add (_standard);
343 _enable_audio_language = new CheckBox(_panel, _("Default audio language"));
344 table->Add(_enable_audio_language, 1, wxEXPAND | wxALIGN_CENTRE_VERTICAL);
345 _audio_language = new LanguageTagWidget(_panel, _("Default audio language to use for new DCPs"), Config::instance()->default_audio_language(), wxString("cmnr-Hant-"));
346 table->Add(_audio_language->sizer());
348 _enable_territory = new CheckBox(_panel, _("Default territory"));
349 table->Add(_enable_territory, 1, wxEXPAND | wxALIGN_CENTRE_VERTICAL);
350 _territory = new RegionSubtagWidget(_panel, _("Default territory to use for new DCPs"), Config::instance()->default_territory(), wxString("cmnr-Hant-"));
351 table->Add(_territory->sizer());
353 table->Add (_enable_metadata["facility"] = new CheckBox (_panel, _("Default facility")), 0, wxALIGN_CENTRE_VERTICAL);
354 table->Add (_metadata["facility"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
356 table->Add (_enable_metadata["studio"] = new CheckBox (_panel, _("Default studio")), 0, wxALIGN_CENTRE_VERTICAL);
357 table->Add (_metadata["studio"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
359 table->Add (_enable_metadata["chain"] = new CheckBox (_panel, _("Default chain")), 0, wxALIGN_CENTRE_VERTICAL);
360 table->Add (_metadata["chain"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
362 table->Add (_enable_metadata["distributor"] = new CheckBox (_panel, _("Default distributor")), 0, wxALIGN_CENTRE_VERTICAL);
363 table->Add (_metadata["distributor"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
365 add_label_to_sizer (table, _panel, _("Default KDM directory"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
366 #ifdef DCPOMATIC_USE_OWN_PICKER
367 _kdm_directory = new DirPickerCtrl (_panel);
369 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
371 table->Add (_kdm_directory, 1, wxEXPAND);
373 add_label_to_sizer (table, _panel, _("Default KDM type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
374 _kdm_type = new KDMChoice (_panel);
375 table->Add (_kdm_type, 1, wxEXPAND);
377 add_label_to_sizer (table, _panel, _("Default KDM duration"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
378 _kdm_duration = new wxSpinCtrl (_panel);
379 _kdm_duration_unit = new wxChoice (_panel, wxID_ANY);
380 auto kdm_duration_sizer = new wxBoxSizer (wxHORIZONTAL);
381 kdm_duration_sizer->Add (_kdm_duration, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
382 kdm_duration_sizer->Add (_kdm_duration_unit, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
383 table->Add (kdm_duration_sizer, 1, wxEXPAND);
385 table->Add (_use_isdcf_name_by_default = new CheckBox(_panel, _("Use ISDCF name by default")), 0, wxALIGN_CENTRE_VERTICAL);
387 _still_length->SetRange (1, 3600);
388 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
390 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
391 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
392 _kdm_type->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_type_changed, this));
393 _kdm_duration_unit->Append (_("days"));
394 _kdm_duration_unit->Append (_("weeks"));
395 _kdm_duration_unit->Append (_("months"));
396 _kdm_duration_unit->Append (_("years"));
398 _kdm_duration->Bind (wxEVT_SPINCTRL, boost::bind(&DefaultsPage::kdm_duration_changed, this));
399 _kdm_duration_unit->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_duration_changed, this));
401 _use_isdcf_name_by_default->bind(&DefaultsPage::use_isdcf_name_by_default_changed, this);
403 for (auto i: DCPContentType::all()) {
404 _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
407 setup_audio_channels_choice (_dcp_audio_channels, 2);
409 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
410 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
412 _j2k_bandwidth->SetRange (50, 250);
413 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
415 _audio_delay->SetRange (-1000, 1000);
416 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
418 _standard->Append (_("SMPTE"));
419 _standard->Append (_("Interop"));
420 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
422 for (auto const& i: _enable_metadata) {
423 i.second->bind(&DefaultsPage::metadata_changed, this);
426 for (auto const& i: _metadata) {
427 i.second->Bind (wxEVT_TEXT, boost::bind(&DefaultsPage::metadata_changed, this));
430 _enable_audio_language->bind(&DefaultsPage::enable_audio_language_toggled, this);
431 _audio_language->Changed.connect(boost::bind(&DefaultsPage::audio_language_changed, this));
433 _enable_territory->bind(&DefaultsPage::enable_territory_toggled, this);
434 _territory->Changed.connect(boost::bind(&DefaultsPage::territory_changed, this));
437 void config_changed () override
439 auto config = Config::instance ();
441 auto const ct = DCPContentType::all ();
442 for (size_t i = 0; i < ct.size(); ++i) {
443 if (ct[i] == config->default_dcp_content_type()) {
444 _dcp_content_type->SetSelection (i);
448 checked_set (_still_length, config->default_still_length ());
449 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
450 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
451 _kdm_type->set (config->default_kdm_type());
452 checked_set (_use_isdcf_name_by_default, config->use_isdcf_name_by_default());
453 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
454 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
455 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
456 checked_set (_audio_delay, config->default_audio_delay ());
457 checked_set (_standard, config->default_interop() ? 1 : 0);
458 auto dal = config->default_audio_language();
459 checked_set(_enable_audio_language, static_cast<bool>(dal));
460 checked_set(_audio_language, dal ? dal : boost::none);
461 auto dt = config->default_territory();
462 checked_set(_enable_territory, static_cast<bool>(dt));
463 checked_set(_territory, dt ? dt : boost::none);
465 auto metadata = config->default_metadata();
467 for (auto const& i: metadata) {
468 _enable_metadata[i.first]->SetValue(true);
469 checked_set (_metadata[i.first], i.second);
472 for (auto const& i: _enable_metadata) {
473 if (metadata.find(i.first) == metadata.end()) {
474 checked_set (i.second, false);
478 for (auto const& i: _metadata) {
479 if (metadata.find(i.first) == metadata.end()) {
480 checked_set (i.second, wxT(""));
484 checked_set (_kdm_duration, config->default_kdm_duration().duration);
485 switch (config->default_kdm_duration().unit) {
486 case RoughDuration::Unit::DAYS:
487 _kdm_duration->SetRange(1, 365);
488 checked_set (_kdm_duration_unit, 0);
490 case RoughDuration::Unit::WEEKS:
491 _kdm_duration->SetRange(1, 52);
492 checked_set (_kdm_duration_unit, 1);
494 case RoughDuration::Unit::MONTHS:
495 _kdm_duration->SetRange(1, 12);
496 checked_set (_kdm_duration_unit, 2);
498 case RoughDuration::Unit::YEARS:
499 _kdm_duration->SetRange(1, 40);
500 checked_set (_kdm_duration_unit, 3);
504 setup_sensitivity ();
507 void kdm_duration_changed ()
509 auto config = Config::instance();
510 auto duration = _kdm_duration->GetValue();
511 RoughDuration::Unit unit = RoughDuration::Unit::DAYS;
512 switch (_kdm_duration_unit->GetSelection()) {
514 unit = RoughDuration::Unit::DAYS;
517 unit = RoughDuration::Unit::WEEKS;
520 unit = RoughDuration::Unit::MONTHS;
523 unit = RoughDuration::Unit::YEARS;
526 config->set_default_kdm_duration (RoughDuration(duration, unit));
529 void j2k_bandwidth_changed ()
531 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
534 void audio_delay_changed ()
536 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
539 void dcp_audio_channels_changed ()
541 int const s = _dcp_audio_channels->GetSelection ();
542 if (s != wxNOT_FOUND) {
543 Config::instance()->set_default_dcp_audio_channels (
544 locale_convert<int>(string_client_data(_dcp_audio_channels->GetClientObject(s)))
549 void directory_changed ()
551 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
554 void kdm_directory_changed ()
556 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
559 void kdm_type_changed ()
561 Config::instance()->set_default_kdm_type(_kdm_type->get());
564 void use_isdcf_name_by_default_changed ()
566 Config::instance()->set_use_isdcf_name_by_default (_use_isdcf_name_by_default->GetValue());
569 void still_length_changed ()
571 Config::instance()->set_default_still_length (_still_length->GetValue ());
574 void dcp_content_type_changed ()
576 auto ct = DCPContentType::all ();
577 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
580 void standard_changed ()
582 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
585 void metadata_changed ()
587 map<string, string> metadata;
588 for (auto const& i: _enable_metadata) {
589 if (i.second->GetValue()) {
590 metadata[i.first] = wx_to_std(_metadata[i.first]->GetValue());
593 Config::instance()->set_default_metadata (metadata);
594 setup_sensitivity ();
597 void enable_audio_language_toggled()
600 audio_language_changed();
603 void audio_language_changed()
605 if (_enable_audio_language->get()) {
606 Config::instance()->set_default_audio_language(_audio_language->get().get_value_or(dcp::LanguageTag("en-US")));
608 Config::instance()->unset_default_audio_language();
612 void enable_territory_toggled()
618 void territory_changed()
620 if (_enable_territory->get()) {
621 Config::instance()->set_default_territory(_territory->get().get_value_or(dcp::LanguageTag::RegionSubtag("US")));
623 Config::instance()->unset_default_territory();
627 void setup_sensitivity ()
629 _audio_language->enable(_enable_audio_language->get());
630 _territory->enable(_enable_territory->get());
631 for (auto const& i: _enable_metadata) {
632 _metadata[i.first]->Enable(i.second->GetValue());
636 wxSpinCtrl* _j2k_bandwidth;
637 wxSpinCtrl* _audio_delay;
638 wxSpinCtrl* _still_length;
639 #ifdef DCPOMATIC_USE_OWN_PICKER
640 DirPickerCtrl* _directory;
641 DirPickerCtrl* _kdm_directory;
643 wxDirPickerCtrl* _directory;
644 wxDirPickerCtrl* _kdm_directory;
646 KDMChoice* _kdm_type;
647 wxSpinCtrl* _kdm_duration;
648 wxChoice* _kdm_duration_unit;
649 CheckBox* _use_isdcf_name_by_default;
650 wxChoice* _dcp_content_type;
651 wxChoice* _dcp_audio_channels;
653 CheckBox* _enable_audio_language;
654 LanguageTagWidget* _audio_language;
655 CheckBox* _enable_territory;
656 RegionSubtagWidget* _territory;
657 map<string, CheckBox*> _enable_metadata;
658 map<string, wxTextCtrl*> _metadata;
662 class EncodingServersPage : public Page
665 EncodingServersPage (wxSize panel_size, int border)
666 : Page (panel_size, border)
669 wxString GetName () const override
675 wxBitmap GetLargeIcon () const override
677 return wxBitmap(icon_path("servers"), wxBITMAP_TYPE_PNG);
682 void setup () override
684 _use_any_servers = new CheckBox (_panel, _("Search network for servers"));
685 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
687 vector<EditableListColumn> columns;
688 columns.push_back (EditableListColumn(_("IP address / host name")));
689 _servers_list = new EditableList<string, ServerDialog> (
692 boost::bind (&Config::servers, Config::instance()),
693 boost::bind (&Config::set_servers, Config::instance(), _1),
694 boost::bind (&EncodingServersPage::server_column, this, _1),
695 EditableListTitle::INVISIBLE,
696 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
699 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
701 _use_any_servers->bind(&EncodingServersPage::use_any_servers_changed, this);
704 void config_changed () override
706 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
707 _servers_list->refresh ();
710 void use_any_servers_changed ()
712 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
715 string server_column (string s)
720 CheckBox* _use_any_servers;
721 EditableList<string, ServerDialog>* _servers_list;
725 class TMSPage : public Page
728 TMSPage (wxSize panel_size, int border)
729 : Page (panel_size, border)
732 wxString GetName () const override
738 wxBitmap GetLargeIcon () const override
740 return wxBitmap(icon_path("tms"), wxBITMAP_TYPE_PNG);
745 void setup () override
747 _upload = new CheckBox (_panel, _("Upload DCP to TMS after creation"));
748 _panel->GetSizer()->Add (_upload, 0, wxALL | wxEXPAND, _border);
750 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
751 table->AddGrowableCol (1, 1);
752 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
754 add_label_to_sizer (table, _panel, _("Protocol"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
755 _tms_protocol = new wxChoice (_panel, wxID_ANY);
756 table->Add (_tms_protocol, 1, wxEXPAND);
758 _tms_passive = new CheckBox(_panel, _("Passive mode"));
759 table->Add(_tms_passive, 1, wxEXPAND);
762 add_label_to_sizer (table, _panel, _("IP address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
763 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
764 table->Add (_tms_ip, 1, wxEXPAND);
766 add_label_to_sizer (table, _panel, _("Target path"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
767 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
768 table->Add (_tms_path, 1, wxEXPAND);
770 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
771 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
772 table->Add (_tms_user, 1, wxEXPAND);
774 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
775 _tms_password = new PasswordEntry (_panel);
776 table->Add (_tms_password->get_panel(), 1, wxEXPAND);
778 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
779 _tms_protocol->Append (_("FTP (for Dolby)"));
781 _upload->bind(&TMSPage::upload_changed, this);
782 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
783 _tms_passive->bind(&TMSPage::tms_passive_changed, this);
785 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
786 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
787 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
788 _tms_password->Changed.connect (boost::bind (&TMSPage::tms_password_changed, this));
791 void config_changed () override
793 auto config = Config::instance ();
795 checked_set (_upload, config->upload_after_make_dcp());
796 checked_set (_tms_protocol, static_cast<int>(config->tms_protocol()));
797 checked_set(_tms_passive, config->tms_protocol() == FileTransferProtocol::FTP && config->tms_passive());
798 checked_set (_tms_ip, config->tms_ip ());
799 checked_set (_tms_path, config->tms_path ());
800 checked_set (_tms_user, config->tms_user ());
801 checked_set (_tms_password, config->tms_password ());
803 _tms_passive->Enable(config->tms_protocol() == FileTransferProtocol::FTP);
806 void upload_changed ()
808 Config::instance()->set_upload_after_make_dcp (_upload->GetValue());
811 void tms_protocol_changed ()
813 Config::instance()->set_tms_protocol(static_cast<FileTransferProtocol>(_tms_protocol->GetSelection()));
816 void tms_passive_changed()
818 Config::instance()->set_tms_passive(_tms_passive->get());
821 void tms_ip_changed ()
823 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
826 void tms_path_changed ()
828 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
831 void tms_user_changed ()
833 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
836 void tms_password_changed ()
838 Config::instance()->set_tms_password (_tms_password->get());
842 CheckBox* _tms_passive;
843 wxChoice* _tms_protocol;
845 wxTextCtrl* _tms_path;
846 wxTextCtrl* _tms_user;
847 PasswordEntry* _tms_password;
851 class EmailPage : public Page
854 EmailPage (wxSize panel_size, int border)
855 : Page (panel_size, border)
858 wxString GetName () const override
864 wxBitmap GetLargeIcon () const override
866 return wxBitmap(icon_path("email"), wxBITMAP_TYPE_PNG);
871 void setup () override
873 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
874 table->AddGrowableCol (1, 1);
875 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
877 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
879 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
880 _server = new wxTextCtrl (_panel, wxID_ANY);
881 s->Add (_server, 1, wxEXPAND | wxALL);
882 add_label_to_sizer (s, _panel, _("port"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
883 _port = new wxSpinCtrl (_panel, wxID_ANY);
884 _port->SetRange (0, 65535);
886 add_label_to_sizer (s, _panel, _("protocol"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
887 _protocol = new wxChoice (_panel, wxID_ANY);
888 /* Make sure this matches the switches in config_changed and port_changed below */
889 _protocol->Append (_("Auto"));
890 _protocol->Append (_("Plain"));
891 _protocol->Append (_("STARTTLS"));
892 _protocol->Append (_("SSL"));
893 s->Add (_protocol, 1, wxALIGN_CENTER_VERTICAL);
894 table->Add (s, 1, wxEXPAND | wxALL);
897 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
898 _user = new wxTextCtrl (_panel, wxID_ANY);
899 table->Add (_user, 1, wxEXPAND | wxALL);
901 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
902 _password = new PasswordEntry (_panel);
903 table->Add (_password->get_panel(), 1, wxEXPAND | wxALL);
905 table->AddSpacer (0);
906 _send_test_email = new Button (_panel, _("Send test email..."));
907 table->Add (_send_test_email);
909 _server->Bind (wxEVT_TEXT, boost::bind(&EmailPage::server_changed, this));
910 _port->Bind (wxEVT_SPINCTRL, boost::bind(&EmailPage::port_changed, this));
911 _protocol->Bind (wxEVT_CHOICE, boost::bind(&EmailPage::protocol_changed, this));
912 _user->Bind (wxEVT_TEXT, boost::bind(&EmailPage::user_changed, this));
913 _password->Changed.connect (boost::bind(&EmailPage::password_changed, this));
914 _send_test_email->Bind (wxEVT_BUTTON, boost::bind(&EmailPage::send_test_email_clicked, this));
917 void config_changed () override
919 auto config = Config::instance ();
921 checked_set (_server, config->mail_server());
922 checked_set (_port, config->mail_port());
923 switch (config->mail_protocol()) {
924 case EmailProtocol::AUTO:
925 checked_set (_protocol, 0);
927 case EmailProtocol::PLAIN:
928 checked_set (_protocol, 1);
930 case EmailProtocol::STARTTLS:
931 checked_set (_protocol, 2);
933 case EmailProtocol::SSL:
934 checked_set (_protocol, 3);
937 checked_set (_user, config->mail_user());
938 checked_set (_password, config->mail_password());
941 void server_changed ()
943 Config::instance()->set_mail_server(wx_to_std(_server->GetValue()));
948 Config::instance()->set_mail_port(_port->GetValue());
951 void protocol_changed ()
953 switch (_protocol->GetSelection()) {
955 Config::instance()->set_mail_protocol(EmailProtocol::AUTO);
958 Config::instance()->set_mail_protocol(EmailProtocol::PLAIN);
961 Config::instance()->set_mail_protocol(EmailProtocol::STARTTLS);
964 Config::instance()->set_mail_protocol(EmailProtocol::SSL);
971 Config::instance()->set_mail_user (wx_to_std (_user->GetValue ()));
974 void password_changed ()
976 Config::instance()->set_mail_password(_password->get());
979 void send_test_email_clicked ()
981 SendTestEmailDialog dialog(_panel);
982 if (dialog.ShowModal() != wxID_OK) {
987 wx_to_std(dialog.from()),
988 { wx_to_std(dialog.to()) },
989 wx_to_std(_("DCP-o-matic test email")),
990 wx_to_std(_("This is a test email from DCP-o-matic."))
992 auto config = Config::instance();
994 email.send(config->mail_server(), config->mail_port(), config->mail_protocol(), config->mail_user(), config->mail_password());
995 } catch (NetworkError& e) {
996 error_dialog(_panel, std_to_wx(e.summary()), std_to_wx(e.detail().get_value_or("")));
998 } catch (std::exception& e) {
999 error_dialog(_panel, _("Test email sending failed."), std_to_wx(e.what()));
1002 error_dialog(_panel, _("Test email sending failed."));
1005 message_dialog(_panel, _("Test email sent."));
1008 wxTextCtrl* _server;
1010 wxChoice* _protocol;
1012 PasswordEntry* _password;
1013 Button* _send_test_email;
1017 class KDMEmailPage : public Page
1021 KDMEmailPage (wxSize panel_size, int border)
1022 #ifdef DCPOMATIC_OSX
1023 /* We have to force both width and height of this one */
1024 : Page (wxSize (panel_size.GetWidth(), 128), border)
1026 : Page (panel_size, border)
1030 wxString GetName () const override
1032 return _("KDM Email");
1035 #ifdef DCPOMATIC_OSX
1036 wxBitmap GetLargeIcon () const override
1038 return wxBitmap(icon_path("kdm_email"), wxBITMAP_TYPE_PNG);
1043 void setup () override
1045 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1046 table->AddGrowableCol (1, 1);
1047 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1049 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1050 _subject = new wxTextCtrl (_panel, wxID_ANY);
1051 table->Add (_subject, 1, wxEXPAND | wxALL);
1053 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1054 _from = new wxTextCtrl (_panel, wxID_ANY);
1055 table->Add (_from, 1, wxEXPAND | wxALL);
1057 vector<EditableListColumn> columns;
1058 columns.push_back (EditableListColumn(_("Address")));
1059 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1060 _cc = new EditableList<string, EmailDialog> (
1063 bind (&Config::kdm_cc, Config::instance()),
1064 bind (&Config::set_kdm_cc, Config::instance(), _1),
1065 [] (string s, int) {
1068 EditableListTitle::VISIBLE,
1069 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
1071 table->Add (_cc, 1, wxEXPAND | wxALL);
1073 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1074 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1075 table->Add (_bcc, 1, wxEXPAND | wxALL);
1077 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1078 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1080 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1081 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1085 _subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1086 _from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1087 _bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1088 _email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1089 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_email, this));
1092 void config_changed () override
1094 auto config = Config::instance ();
1096 checked_set (_subject, config->kdm_subject ());
1097 checked_set (_from, config->kdm_from ());
1098 checked_set (_bcc, config->kdm_bcc ());
1099 checked_set (_email, Config::instance()->kdm_email ());
1102 void kdm_subject_changed ()
1104 Config::instance()->set_kdm_subject (wx_to_std (_subject->GetValue ()));
1107 void kdm_from_changed ()
1109 Config::instance()->set_kdm_from (wx_to_std (_from->GetValue ()));
1112 void kdm_bcc_changed ()
1114 Config::instance()->set_kdm_bcc (wx_to_std (_bcc->GetValue ()));
1117 void kdm_email_changed ()
1119 if (_email->GetValue().IsEmpty ()) {
1120 /* Sometimes we get sent an erroneous notification that the email
1121 is empty; I don't know why.
1125 Config::instance()->set_kdm_email (wx_to_std (_email->GetValue ()));
1130 Config::instance()->reset_kdm_email ();
1131 checked_set (_email, Config::instance()->kdm_email ());
1134 wxTextCtrl* _subject;
1136 EditableList<string, EmailDialog>* _cc;
1139 wxButton* _reset_email;
1143 class NotificationsPage : public Page
1146 NotificationsPage (wxSize panel_size, int border)
1147 #ifdef DCPOMATIC_OSX
1148 /* We have to force both width and height of this one */
1149 : Page (wxSize (panel_size.GetWidth(), 128), border)
1151 : Page (panel_size, border)
1155 wxString GetName () const override
1157 return _("Notifications");
1160 #ifdef DCPOMATIC_OSX
1161 wxBitmap GetLargeIcon () const override
1163 return wxBitmap(icon_path("notifications"), wxBITMAP_TYPE_PNG);
1168 void setup () override
1170 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1171 table->AddGrowableCol (1, 1);
1172 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1174 _enable_message_box = new CheckBox (_panel, _("Message box"));
1175 table->Add (_enable_message_box, 1, wxEXPAND | wxALL);
1176 table->AddSpacer (0);
1178 _enable_email = new CheckBox (_panel, _("Email"));
1179 table->Add (_enable_email, 1, wxEXPAND | wxALL);
1180 table->AddSpacer (0);
1182 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1183 _subject = new wxTextCtrl (_panel, wxID_ANY);
1184 table->Add (_subject, 1, wxEXPAND | wxALL);
1186 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1187 _from = new wxTextCtrl (_panel, wxID_ANY);
1188 table->Add (_from, 1, wxEXPAND | wxALL);
1190 add_label_to_sizer (table, _panel, _("To address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1191 _to = new wxTextCtrl (_panel, wxID_ANY);
1192 table->Add (_to, 1, wxEXPAND | wxALL);
1194 vector<EditableListColumn> columns;
1195 columns.push_back (EditableListColumn(_("Address")));
1196 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1197 _cc = new EditableList<string, EmailDialog> (
1200 bind (&Config::notification_cc, Config::instance()),
1201 bind (&Config::set_notification_cc, Config::instance(), _1),
1202 [] (string s, int) {
1205 EditableListTitle::VISIBLE,
1206 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
1208 table->Add (_cc, 1, wxEXPAND | wxALL);
1210 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1211 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1212 table->Add (_bcc, 1, wxEXPAND | wxALL);
1214 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1215 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1217 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1218 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1222 _enable_message_box->bind(&NotificationsPage::type_changed, this, _enable_message_box, Config::MESSAGE_BOX);
1223 _enable_email->bind(&NotificationsPage::type_changed, this, _enable_email, Config::EMAIL);
1225 _subject->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_subject_changed, this));
1226 _from->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_from_changed, this));
1227 _to->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_to_changed, this));
1228 _bcc->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_bcc_changed, this));
1229 _email->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_email_changed, this));
1230 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&NotificationsPage::reset_email, this));
1232 setup_sensitivity ();
1235 void setup_sensitivity ()
1237 bool const s = _enable_email->GetValue();
1238 _subject->Enable(s);
1244 _reset_email->Enable(s);
1247 void config_changed () override
1249 auto config = Config::instance ();
1251 checked_set (_enable_message_box, config->notification(Config::MESSAGE_BOX));
1252 checked_set (_enable_email, config->notification(Config::EMAIL));
1253 checked_set (_subject, config->notification_subject ());
1254 checked_set (_from, config->notification_from ());
1255 checked_set (_to, config->notification_to ());
1256 checked_set (_bcc, config->notification_bcc ());
1257 checked_set (_email, Config::instance()->notification_email ());
1259 setup_sensitivity ();
1262 void notification_subject_changed ()
1264 Config::instance()->set_notification_subject(wx_to_std(_subject->GetValue()));
1267 void notification_from_changed ()
1269 Config::instance()->set_notification_from(wx_to_std(_from->GetValue()));
1272 void notification_to_changed ()
1274 Config::instance()->set_notification_to(wx_to_std(_to->GetValue()));
1277 void notification_bcc_changed ()
1279 Config::instance()->set_notification_bcc(wx_to_std(_bcc->GetValue()));
1282 void notification_email_changed ()
1284 if (_email->GetValue().IsEmpty()) {
1285 /* Sometimes we get sent an erroneous notification that the email
1286 is empty; I don't know why.
1290 Config::instance()->set_notification_email(wx_to_std(_email->GetValue()));
1295 Config::instance()->reset_notification_email();
1296 checked_set (_email, Config::instance()->notification_email());
1299 void type_changed (CheckBox* b, Config::Notification n)
1301 Config::instance()->set_notification(n, b->GetValue());
1302 setup_sensitivity ();
1305 CheckBox* _enable_message_box;
1306 CheckBox* _enable_email;
1308 wxTextCtrl* _subject;
1311 EditableList<string, EmailDialog>* _cc;
1314 wxButton* _reset_email;
1318 class CoverSheetPage : public Page
1322 CoverSheetPage (wxSize panel_size, int border)
1323 #ifdef DCPOMATIC_OSX
1324 /* We have to force both width and height of this one */
1325 : Page (wxSize (panel_size.GetWidth(), 128), border)
1327 : Page (panel_size, border)
1331 wxString GetName () const override
1333 return _("Cover Sheet");
1336 #ifdef DCPOMATIC_OSX
1337 wxBitmap GetLargeIcon () const override
1339 return wxBitmap(icon_path("cover_sheet"), wxBITMAP_TYPE_PNG);
1344 void setup () override
1346 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1347 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
1349 _reset_cover_sheet = new Button (_panel, _("Reset to default text"));
1350 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
1352 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
1353 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
1356 void config_changed () override
1358 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1361 void cover_sheet_changed ()
1363 if (_cover_sheet->GetValue().IsEmpty ()) {
1364 /* Sometimes we get sent an erroneous notification that the cover sheet
1365 is empty; I don't know why.
1369 Config::instance()->set_cover_sheet(wx_to_std(_cover_sheet->GetValue()));
1372 void reset_cover_sheet ()
1374 Config::instance()->reset_cover_sheet();
1375 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1378 wxTextCtrl* _cover_sheet;
1379 wxButton* _reset_cover_sheet;
1383 class IdentifiersPage : public Page
1386 IdentifiersPage (wxSize panel_size, int border)
1387 : Page (panel_size, border)
1390 wxString GetName () const override
1392 return _("Identifiers");
1395 #ifdef DCPOMATIC_OSX
1396 wxBitmap GetLargeIcon () const override
1398 return wxBitmap(icon_path("identifiers"), wxBITMAP_TYPE_PNG);
1403 void setup () override
1405 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1406 table->AddGrowableCol (1, 1);
1408 add_label_to_sizer (table, _panel, _("Issuer"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1409 _issuer = new wxTextCtrl (_panel, wxID_ANY);
1410 _issuer->SetToolTip (_("This will be written to the DCP's XML files as the <Issuer>. If it is blank, a default value mentioning DCP-o-matic will be used."));
1411 table->Add (_issuer, 1, wxALL | wxEXPAND);
1413 add_label_to_sizer (table, _panel, _("Creator"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1414 _creator = new wxTextCtrl (_panel, wxID_ANY);
1415 _creator->SetToolTip (_("This will be written to the DCP's XML files as the <Creator>. If it is blank, a default value mentioning DCP-o-matic will be used."));
1416 table->Add (_creator, 1, wxALL | wxEXPAND);
1418 add_label_to_sizer (table, _panel, _("Company name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1419 _company_name = new wxTextCtrl (_panel, wxID_ANY);
1420 _company_name->SetToolTip (_("This will be written to the DCP's MXF files as the 'company name'. If it is blank, a default value mentioning libdcp (an internal DCP-o-matic library) will be used."));
1421 table->Add (_company_name, 1, wxALL | wxEXPAND);
1423 add_label_to_sizer (table, _panel, _("Product name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1424 _product_name = new wxTextCtrl (_panel, wxID_ANY);
1425 _product_name->SetToolTip (_("This will be written to the DCP's MXF files as the 'product name'. If it is blank, a default value mentioning libdcp (an internal DCP-o-matic library) will be used."));
1426 table->Add (_product_name, 1, wxALL | wxEXPAND);
1428 add_label_to_sizer (table, _panel, _("Product version"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1429 _product_version = new wxTextCtrl (_panel, wxID_ANY);
1430 _product_version->SetToolTip (_("This will be written to the DCP's MXF files as the 'product version'. If it is blank, a default value mentioning libdcp (an internal DCP-o-matic library) will be used."));
1431 table->Add (_product_version, 1, wxALL | wxEXPAND);
1433 add_label_to_sizer (table, _panel, _("JPEG2000 comment"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1434 _j2k_comment = new wxTextCtrl (_panel, wxID_ANY);
1435 _j2k_comment->SetToolTip (_("This will be written to the DCP's JPEG2000 data as a comment. If it is blank, a default value mentioning libdcp (an internal DCP-o-matic library) will be used."));
1436 table->Add (_j2k_comment, 1, wxALL | wxEXPAND);
1438 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1440 _issuer->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::issuer_changed, this));
1441 _creator->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::creator_changed, this));
1442 _company_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::company_name_changed, this));
1443 _product_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_name_changed, this));
1444 _product_version->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_version_changed, this));
1445 _j2k_comment->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::j2k_comment_changed, this));
1448 void config_changed () override
1450 auto config = Config::instance ();
1451 checked_set (_issuer, config->dcp_issuer ());
1452 checked_set (_creator, config->dcp_creator ());
1453 checked_set (_company_name, config->dcp_company_name ());
1454 checked_set (_product_name, config->dcp_product_name ());
1455 checked_set (_product_version, config->dcp_product_version ());
1456 checked_set (_j2k_comment, config->dcp_j2k_comment ());
1459 void issuer_changed ()
1461 Config::instance()->set_dcp_issuer(wx_to_std(_issuer->GetValue()));
1464 void creator_changed ()
1466 Config::instance()->set_dcp_creator(wx_to_std(_creator->GetValue()));
1469 void company_name_changed ()
1471 Config::instance()->set_dcp_company_name(wx_to_std(_company_name->GetValue()));
1474 void product_name_changed ()
1476 Config::instance()->set_dcp_product_name(wx_to_std(_product_name->GetValue()));
1479 void product_version_changed ()
1481 Config::instance()->set_dcp_product_version(wx_to_std(_product_version->GetValue()));
1484 void j2k_comment_changed ()
1486 Config::instance()->set_dcp_j2k_comment (wx_to_std(_j2k_comment->GetValue()));
1489 wxTextCtrl* _issuer;
1490 wxTextCtrl* _creator;
1491 wxTextCtrl* _company_name;
1492 wxTextCtrl* _product_name;
1493 wxTextCtrl* _product_version;
1494 wxTextCtrl* _j2k_comment;
1498 class NonStandardPage : public Page
1501 NonStandardPage(wxSize panel_size, int border)
1502 : Page(panel_size, border)
1505 wxString GetName() const override
1507 return _("Non-standard");
1510 #ifdef DCPOMATIC_OSX
1511 wxBitmap GetLargeIcon() const override
1513 return wxBitmap(icon_path("non_standard"), wxBITMAP_TYPE_PNG);
1518 void setup() override
1520 auto table = new wxFlexGridSizer(2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1521 table->AddGrowableCol(1, 1);
1522 _panel->GetSizer()->Add(table, 1, wxALL | wxEXPAND, _border);
1525 add_label_to_sizer(table, _panel, _("Maximum JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1526 auto s = new wxBoxSizer(wxHORIZONTAL);
1527 _maximum_j2k_bandwidth = new wxSpinCtrl(_panel);
1528 s->Add(_maximum_j2k_bandwidth, 1);
1529 add_label_to_sizer(s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxALIGN_CENTRE_VERTICAL);
1533 auto checkbox = [this, table](wxString name, CheckBox*& variable) {
1534 variable = new CheckBox(_panel, name);
1535 table->Add(variable, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1536 table->AddSpacer(0);
1539 checkbox(_("Allow any DCP frame rate"), _allow_any_dcp_frame_rate);
1541 _allow_any_container = new CheckBox(_panel, _("Allow full-frame and non-standard container ratios"));
1542 table->Add(_allow_any_container, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1543 auto restart = new StaticText(_panel, _("(restart DCP-o-matic to see all ratios)"));
1544 auto font = restart->GetFont();
1545 font.SetStyle(wxFONTSTYLE_ITALIC);
1546 font.SetPointSize(font.GetPointSize() - 1);
1547 restart->SetFont(font);
1548 table->Add(restart, 1, wxALIGN_CENTRE_VERTICAL | wxBOTTOM, DCPOMATIC_CHECKBOX_BOTTOM_PAD);
1549 restart->SetFont(font);
1551 checkbox(_("Allow creation of DCPs with 96kHz audio"), _allow_96khz_audio);
1552 checkbox(_("Allow mapping to all audio channels"), _use_all_audio_channels);
1553 checkbox(_("Allow use of SMPTE Bv2.0"), _allow_smpte_bv20);
1556 add_label_to_sizer(table, _panel, _("ISDCF name part length"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1557 auto s = new wxBoxSizer(wxHORIZONTAL);
1558 _isdcf_name_part_length = new wxSpinCtrl(_panel);
1559 s->Add(_isdcf_name_part_length, 1);
1563 _maximum_j2k_bandwidth->SetRange(1, 1000);
1564 _maximum_j2k_bandwidth->Bind(wxEVT_SPINCTRL, boost::bind(&NonStandardPage::maximum_j2k_bandwidth_changed, this));
1565 _allow_any_dcp_frame_rate->bind(&NonStandardPage::allow_any_dcp_frame_rate_changed, this);
1566 _allow_any_container->bind(&NonStandardPage::allow_any_container_changed, this);
1567 _allow_96khz_audio->bind(&NonStandardPage::allow_96khz_audio_changed, this);
1568 _use_all_audio_channels->bind(&NonStandardPage::use_all_channels_changed, this);
1569 _allow_smpte_bv20->bind(&NonStandardPage::allow_smpte_bv20_changed, this);
1570 _isdcf_name_part_length->SetRange(1, 256);
1571 _isdcf_name_part_length->Bind(wxEVT_SPINCTRL, boost::bind(&NonStandardPage::isdcf_name_part_length_changed, this));
1574 void config_changed() override
1576 auto config = Config::instance();
1578 checked_set(_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1579 checked_set(_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate());
1580 checked_set(_allow_any_container, config->allow_any_container());
1581 checked_set(_allow_96khz_audio, config->allow_96khz_audio());
1582 checked_set(_use_all_audio_channels, config->use_all_audio_channels());
1583 checked_set(_allow_smpte_bv20, config->allow_smpte_bv20());
1584 checked_set(_isdcf_name_part_length, config->isdcf_name_part_length());
1587 void maximum_j2k_bandwidth_changed()
1589 Config::instance()->set_maximum_j2k_bandwidth(_maximum_j2k_bandwidth->GetValue() * 1000000);
1592 void allow_any_dcp_frame_rate_changed()
1594 Config::instance()->set_allow_any_dcp_frame_rate(_allow_any_dcp_frame_rate->GetValue());
1597 void allow_any_container_changed()
1599 Config::instance()->set_allow_any_container(_allow_any_container->GetValue());
1602 void allow_96khz_audio_changed()
1604 Config::instance()->set_allow_96hhz_audio(_allow_96khz_audio->GetValue());
1607 void use_all_channels_changed()
1609 Config::instance()->set_use_all_audio_channels(_use_all_audio_channels->GetValue());
1612 void allow_smpte_bv20_changed()
1614 Config::instance()->set_allow_smpte_bv20(_allow_smpte_bv20->GetValue());
1617 void isdcf_name_part_length_changed()
1619 Config::instance()->set_isdcf_name_part_length(_isdcf_name_part_length->GetValue());
1622 wxSpinCtrl* _maximum_j2k_bandwidth = nullptr;
1623 CheckBox* _allow_any_dcp_frame_rate = nullptr;
1624 CheckBox* _allow_any_container = nullptr;
1625 CheckBox* _allow_96khz_audio = nullptr;
1626 CheckBox* _use_all_audio_channels = nullptr;
1627 CheckBox* _allow_smpte_bv20 = nullptr;
1628 wxSpinCtrl* _isdcf_name_part_length = nullptr;
1633 /** @class AdvancedPage
1634 * @brief Advanced page of the preferences dialog.
1636 class AdvancedPage : public Page
1639 AdvancedPage (wxSize panel_size, int border)
1640 : Page (panel_size, border)
1643 wxString GetName () const override
1645 return _("Advanced");
1648 #ifdef DCPOMATIC_OSX
1649 wxBitmap GetLargeIcon () const override
1651 return wxBitmap(icon_path("advanced"), wxBITMAP_TYPE_PNG);
1656 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1658 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1660 flags |= wxALIGN_RIGHT;
1663 wxStaticText* m = new StaticText (parent, text);
1664 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1667 void setup () override
1669 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1670 table->AddGrowableCol (1, 1);
1671 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1673 add_label_to_sizer (table, _panel, _("Video display mode"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1674 _video_display_mode = new wxChoice (_panel, wxID_ANY);
1675 table->Add (_video_display_mode);
1677 auto restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to change display mode)"), false);
1678 auto font = restart->GetFont();
1679 font.SetStyle (wxFONTSTYLE_ITALIC);
1680 font.SetPointSize (font.GetPointSize() - 1);
1681 restart->SetFont (font);
1682 table->AddSpacer (0);
1684 _show_experimental_audio_processors = new CheckBox (_panel, _("Show experimental audio processors"));
1685 table->Add (_show_experimental_audio_processors, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1686 table->AddSpacer (0);
1688 _only_servers_encode = new CheckBox (_panel, _("Only servers encode"));
1689 table->Add (_only_servers_encode, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1690 table->AddSpacer (0);
1693 add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1694 auto s = new wxBoxSizer (wxHORIZONTAL);
1695 _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
1696 s->Add (_frames_in_memory_multiplier, 1);
1701 auto format = create_label (_panel, _("DCP metadata filename format"), true);
1702 #ifdef DCPOMATIC_OSX
1703 auto align = new wxBoxSizer (wxHORIZONTAL);
1704 align->Add (format, 0, wxTOP, 2);
1705 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1707 table->Add (format, 0, wxTOP | wxLEFT | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1709 dcp::NameFormat::Map titles;
1710 titles['t'] = wx_to_std (_("type (cpl/pkl)"));
1711 dcp::NameFormat::Map examples;
1712 examples['t'] = "cpl";
1713 _dcp_metadata_filename_format = new NameFormatEditor (
1714 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1716 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1720 auto format = create_label (_panel, _("DCP asset filename format"), true);
1721 #ifdef DCPOMATIC_OSX
1722 auto align = new wxBoxSizer (wxHORIZONTAL);
1723 align->Add (format, 0, wxTOP, 2);
1724 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1726 table->Add (format, 0, wxTOP | wxLEFT | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1728 dcp::NameFormat::Map titles;
1729 titles['t'] = wx_to_std (_("type (j2c/pcm/sub)"));
1730 titles['r'] = wx_to_std (_("reel number"));
1731 titles['n'] = wx_to_std (_("number of reels"));
1732 titles['c'] = wx_to_std (_("content filename"));
1733 dcp::NameFormat::Map examples;
1734 examples['t'] = "j2c";
1735 examples['r'] = "1";
1736 examples['n'] = "4";
1737 examples['c'] = "myfile.mp4";
1738 _dcp_asset_filename_format = new NameFormatEditor (
1739 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1741 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1745 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1746 auto t = new wxFlexGridSizer (2);
1747 _log_general = new CheckBox (_panel, _("General"));
1748 t->Add (_log_general, 1, wxEXPAND | wxALL);
1749 _log_warning = new CheckBox (_panel, _("Warnings"));
1750 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1751 _log_error = new CheckBox (_panel, _("Errors"));
1752 t->Add (_log_error, 1, wxEXPAND | wxALL);
1753 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1754 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
1755 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1756 _log_debug_threed = new CheckBox (_panel, _("Debug: 3D"));
1757 t->Add (_log_debug_threed, 1, wxEXPAND | wxALL);
1758 _log_debug_encode = new CheckBox (_panel, _("Debug: encode"));
1759 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1760 _log_debug_email = new CheckBox (_panel, _("Debug: email sending"));
1761 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1762 _log_debug_video_view = new CheckBox (_panel, _("Debug: video view"));
1763 t->Add (_log_debug_video_view, 1, wxEXPAND | wxALL);
1764 _log_debug_player = new CheckBox (_panel, _("Debug: player"));
1765 t->Add (_log_debug_player, 1, wxEXPAND | wxALL);
1766 _log_debug_audio_analysis = new CheckBox (_panel, _("Debug: audio analysis"));
1767 t->Add (_log_debug_audio_analysis, 1, wxEXPAND | wxALL);
1768 table->Add (t, 0, wxALL, 6);
1771 #ifdef DCPOMATIC_WINDOWS
1772 _win32_console = new CheckBox (_panel, _("Open console window"));
1773 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1774 table->AddSpacer (0);
1777 _video_display_mode->Append (_("Simple (safer)"));
1778 #if wxCHECK_VERSION(3, 1, 0)
1779 _video_display_mode->Append (_("OpenGL (faster)"));
1781 _video_display_mode->Bind (wxEVT_CHOICE, boost::bind(&AdvancedPage::video_display_mode_changed, this));
1782 _show_experimental_audio_processors->bind(&AdvancedPage::show_experimental_audio_processors_changed, this);
1783 _only_servers_encode->bind(&AdvancedPage::only_servers_encode_changed, this);
1784 _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
1785 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1786 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1787 _log_general->bind(&AdvancedPage::log_changed, this);
1788 _log_warning->bind(&AdvancedPage::log_changed, this);
1789 _log_error->bind(&AdvancedPage::log_changed, this);
1790 _log_timing->bind(&AdvancedPage::log_changed, this);
1791 _log_debug_threed->bind(&AdvancedPage::log_changed, this);
1792 _log_debug_encode->bind(&AdvancedPage::log_changed, this);
1793 _log_debug_email->bind(&AdvancedPage::log_changed, this);
1794 _log_debug_video_view->bind(&AdvancedPage::log_changed, this);
1795 _log_debug_player->bind(&AdvancedPage::log_changed, this);
1796 _log_debug_audio_analysis->bind(&AdvancedPage::log_changed, this);
1797 #ifdef DCPOMATIC_WINDOWS
1798 _win32_console->bind(&AdvancedPage::win32_console_changed, this);
1802 void config_changed () override
1804 auto config = Config::instance ();
1806 switch (config->video_view_type()) {
1807 case Config::VIDEO_VIEW_SIMPLE:
1808 checked_set (_video_display_mode, 0);
1810 case Config::VIDEO_VIEW_OPENGL:
1811 checked_set (_video_display_mode, 1);
1814 checked_set (_show_experimental_audio_processors, config->show_experimental_audio_processors ());
1815 checked_set (_only_servers_encode, config->only_servers_encode ());
1816 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1817 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1818 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1819 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1820 checked_set (_log_debug_threed, config->log_types() & LogEntry::TYPE_DEBUG_THREE_D);
1821 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1822 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1823 checked_set (_log_debug_video_view, config->log_types() & LogEntry::TYPE_DEBUG_VIDEO_VIEW);
1824 checked_set (_log_debug_player, config->log_types() & LogEntry::TYPE_DEBUG_PLAYER);
1825 checked_set (_log_debug_audio_analysis, config->log_types() & LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS);
1826 checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
1827 #ifdef DCPOMATIC_WINDOWS
1828 checked_set (_win32_console, config->win32_console());
1832 void video_display_mode_changed ()
1834 if (_video_display_mode->GetSelection() == 0) {
1835 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_SIMPLE);
1837 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_OPENGL);
1841 void frames_in_memory_multiplier_changed ()
1843 Config::instance()->set_frames_in_memory_multiplier(_frames_in_memory_multiplier->GetValue());
1846 void show_experimental_audio_processors_changed ()
1848 Config::instance()->set_show_experimental_audio_processors(_show_experimental_audio_processors->GetValue());
1851 void only_servers_encode_changed ()
1853 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue());
1856 void dcp_metadata_filename_format_changed ()
1858 Config::instance()->set_dcp_metadata_filename_format(_dcp_metadata_filename_format->get());
1861 void dcp_asset_filename_format_changed ()
1863 Config::instance()->set_dcp_asset_filename_format(_dcp_asset_filename_format->get());
1869 if (_log_general->GetValue ()) {
1870 types |= LogEntry::TYPE_GENERAL;
1872 if (_log_warning->GetValue ()) {
1873 types |= LogEntry::TYPE_WARNING;
1875 if (_log_error->GetValue ()) {
1876 types |= LogEntry::TYPE_ERROR;
1878 if (_log_timing->GetValue ()) {
1879 types |= LogEntry::TYPE_TIMING;
1881 if (_log_debug_threed->GetValue ()) {
1882 types |= LogEntry::TYPE_DEBUG_THREE_D;
1884 if (_log_debug_encode->GetValue ()) {
1885 types |= LogEntry::TYPE_DEBUG_ENCODE;
1887 if (_log_debug_email->GetValue ()) {
1888 types |= LogEntry::TYPE_DEBUG_EMAIL;
1890 if (_log_debug_video_view->GetValue()) {
1891 types |= LogEntry::TYPE_DEBUG_VIDEO_VIEW;
1893 if (_log_debug_player->GetValue()) {
1894 types |= LogEntry::TYPE_DEBUG_PLAYER;
1896 if (_log_debug_audio_analysis->GetValue()) {
1897 types |= LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS;
1899 Config::instance()->set_log_types (types);
1902 #ifdef DCPOMATIC_WINDOWS
1903 void win32_console_changed ()
1905 Config::instance()->set_win32_console(_win32_console->GetValue());
1909 wxChoice* _video_display_mode = nullptr;
1910 wxSpinCtrl* _frames_in_memory_multiplier = nullptr;
1911 CheckBox* _show_experimental_audio_processors = nullptr;
1912 CheckBox* _only_servers_encode = nullptr;
1913 NameFormatEditor* _dcp_metadata_filename_format = nullptr;
1914 NameFormatEditor* _dcp_asset_filename_format = nullptr;
1915 CheckBox* _log_general = nullptr;
1916 CheckBox* _log_warning = nullptr;
1917 CheckBox* _log_error = nullptr;
1918 CheckBox* _log_timing = nullptr;
1919 CheckBox* _log_debug_threed = nullptr;
1920 CheckBox* _log_debug_encode = nullptr;
1921 CheckBox* _log_debug_email = nullptr;
1922 CheckBox* _log_debug_video_view = nullptr;
1923 CheckBox* _log_debug_player = nullptr;
1924 CheckBox* _log_debug_audio_analysis = nullptr;
1925 #ifdef DCPOMATIC_WINDOWS
1926 CheckBox* _win32_console = nullptr;
1931 wxPreferencesEditor*
1932 create_full_config_dialog ()
1934 auto e = new wxPreferencesEditor ();
1936 #ifdef DCPOMATIC_OSX
1937 /* Width that we force some of the config panels to be on OSX so that
1938 the containing window doesn't shrink too much when we select those panels.
1939 This is obviously an unpleasant hack.
1941 wxSize ps = wxSize(900, -1);
1942 int const border = 16;
1944 wxSize ps = wxSize (-1, -1);
1945 int const border = 8;
1948 e->AddPage (new FullGeneralPage (ps, border));
1949 e->AddPage (new SoundPage (ps, border));
1950 e->AddPage (new DefaultsPage (ps, border));
1951 e->AddPage (new EncodingServersPage(ps, border));
1952 #ifdef DCPOMATIC_GROK
1953 e->AddPage (new GPUPage (ps, border));
1955 e->AddPage (new KeysPage (ps, border));
1956 e->AddPage (new TMSPage (ps, border));
1957 e->AddPage (new EmailPage (ps, border));
1958 e->AddPage (new KDMEmailPage (ps, border));
1959 e->AddPage (new NotificationsPage (ps, border));
1960 e->AddPage (new CoverSheetPage (ps, border));
1961 e->AddPage (new IdentifiersPage (ps, border));
1962 e->AddPage (new NonStandardPage (ps, border));
1963 e->AddPage (new AdvancedPage (ps, border));