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 "wx_variant.h"
53 #include "lib/config.h"
54 #include "lib/cross.h"
55 #include "lib/dcp_content_type.h"
56 #include "lib/email.h"
57 #include "lib/exceptions.h"
58 #include "lib/filter.h"
60 #include "lib/ratio.h"
62 #include <dcp/certificate_chain.h>
63 #include <dcp/exceptions.h>
64 #include <dcp/filesystem.h>
65 #include <dcp/locale_convert.h>
66 #include <dcp/warnings.h>
67 LIBDCP_DISABLE_WARNINGS
68 #include <wx/filepicker.h>
69 #include <wx/preferences.h>
70 #include <wx/spinctrl.h>
71 #include <wx/stdpaths.h>
72 LIBDCP_ENABLE_WARNINGS
74 #include <boost/filesystem.hpp>
84 using std::shared_ptr;
88 using boost::optional;
89 #if BOOST_VERSION >= 106100
90 using namespace boost::placeholders;
92 using dcp::locale_convert;
95 class FullGeneralPage : public GeneralPage
98 FullGeneralPage (wxSize panel_size, int border)
99 : GeneralPage (panel_size, border)
103 void setup () override
105 auto table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
106 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
109 add_language_controls (table, r);
111 add_label_to_sizer(table, _panel, variant::wx::insert_dcpomatic(_("Number of threads %s should use")), true, wxGBPosition(r, 0));
112 _master_encoding_threads = new wxSpinCtrl (_panel);
113 table->Add (_master_encoding_threads, wxGBPosition (r, 1));
116 add_label_to_sizer(table, _panel, variant::wx::insert_dcpomatic_encode_server(_("Number of threads %s should use")), true, wxGBPosition(r, 0));
117 _server_encoding_threads = new wxSpinCtrl (_panel);
118 table->Add (_server_encoding_threads, wxGBPosition (r, 1));
121 add_label_to_sizer (table, _panel, _("Configuration file"), true, wxGBPosition (r, 0));
122 _config_file = new FilePickerCtrl(_panel, _("Select configuration file"), "*.xml", true, false, "ConfigFilePath");
123 table->Add (_config_file, wxGBPosition (r, 1));
126 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
127 _cinemas_file = new FilePickerCtrl(_panel, _("Select cinema and screen database file"), "*.xml", true, false, "CinemaDatabasePath");
128 table->Add (_cinemas_file, wxGBPosition (r, 1));
129 auto export_cinemas = new Button (_panel, _("Export..."));
130 table->Add (export_cinemas, wxGBPosition (r, 2));
133 add_label_to_sizer(table, _panel, _("Default \"add file\" location"), true, wxGBPosition(r, 0));
134 _default_add_file_location = new Choice(_panel);
135 table->Add(_default_add_file_location, wxGBPosition(r, 1));
138 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
139 _analyse_ebur128 = new CheckBox (_panel, _("Find integrated loudness, true peak and loudness range when analysing audio"));
140 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
144 _automatic_audio_analysis = new CheckBox (_panel, _("Automatically analyse content audio"));
145 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
148 add_update_controls (table, r);
150 _default_add_file_location->add(_("Same place as last time"));
151 _default_add_file_location->add(_("Same place as project"));
152 _default_add_file_location->bind(&FullGeneralPage::default_add_file_location_changed, this);
154 _config_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::config_file_changed, this));
155 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::cinemas_file_changed, this));
157 _master_encoding_threads->SetRange (1, 128);
158 _master_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::master_encoding_threads_changed, this));
159 _server_encoding_threads->SetRange (1, 128);
160 _server_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::server_encoding_threads_changed, this));
161 export_cinemas->Bind (wxEVT_BUTTON, boost::bind (&FullGeneralPage::export_cinemas_file, this));
163 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
164 _analyse_ebur128->bind(&FullGeneralPage::analyse_ebur128_changed, this);
166 _automatic_audio_analysis->bind(&FullGeneralPage::automatic_audio_analysis_changed, this);
169 void config_changed () override
171 auto config = Config::instance ();
173 checked_set (_master_encoding_threads, config->master_encoding_threads ());
174 checked_set (_server_encoding_threads, config->server_encoding_threads ());
175 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
176 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
178 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
179 checked_set (_config_file, config->config_read_file());
180 checked_set (_cinemas_file, config->cinemas_file());
181 checked_set(_default_add_file_location, config->default_add_file_location() == Config::DefaultAddFileLocation::SAME_AS_LAST_TIME ? 0 : 1);
183 GeneralPage::config_changed ();
186 void export_cinemas_file ()
189 _panel, _("Select Cinemas File"), wxEmptyString, wxEmptyString, wxT("XML files (*.xml)|*.xml"),
190 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
193 if (dialog.ShowModal() == wxID_OK) {
194 dcp::filesystem::copy_file(Config::instance()->cinemas_file(), wx_to_std(dialog.GetPath()), boost::filesystem::copy_option::overwrite_if_exists);
198 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
199 void analyse_ebur128_changed ()
201 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue());
205 void automatic_audio_analysis_changed ()
207 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue());
210 void master_encoding_threads_changed ()
212 Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue());
215 void server_encoding_threads_changed ()
217 Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue());
220 void config_file_changed ()
222 auto config = Config::instance();
223 auto const new_file = _config_file->path();
224 if (!new_file || *new_file == config->config_read_file()) {
227 bool copy_and_link = true;
228 if (dcp::filesystem::exists(*new_file)) {
229 ConfigMoveDialog dialog(_panel, *new_file);
230 if (dialog.ShowModal() == wxID_OK) {
231 copy_and_link = false;
237 if (new_file != config->config_read_file()) {
238 config->copy_and_link(*new_file);
241 config->link(*new_file);
245 void cinemas_file_changed ()
247 if (auto path = _cinemas_file->path()) {
248 Config::instance()->set_cinemas_file(*path);
252 void default_add_file_location_changed()
254 Config::instance()->set_default_add_file_location(
255 _default_add_file_location->get().get_value_or(0) == 0 ? Config::DefaultAddFileLocation::SAME_AS_LAST_TIME : Config::DefaultAddFileLocation::SAME_AS_PROJECT
259 Choice* _default_add_file_location;
260 wxSpinCtrl* _master_encoding_threads;
261 wxSpinCtrl* _server_encoding_threads;
262 FilePickerCtrl* _config_file;
263 FilePickerCtrl* _cinemas_file;
264 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
265 CheckBox* _analyse_ebur128;
267 CheckBox* _automatic_audio_analysis;
271 class DefaultsPage : public Page
274 DefaultsPage (wxSize panel_size, int border)
275 : Page (panel_size, border)
278 wxString GetName () const override
280 return _("Defaults");
284 wxBitmap GetLargeIcon () const override
286 return wxBitmap(icon_path("defaults"), wxBITMAP_TYPE_PNG);
291 void setup () override
293 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
294 table->AddGrowableCol (1, 1);
295 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
298 add_label_to_sizer (table, _panel, _("Default duration of still images"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
299 auto s = new wxBoxSizer (wxHORIZONTAL);
300 _still_length = new wxSpinCtrl (_panel);
301 s->Add (_still_length);
302 add_label_to_sizer (s, _panel, _("s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
306 add_label_to_sizer (table, _panel, _("Default directory for new films"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
307 #ifdef DCPOMATIC_USE_OWN_PICKER
308 _directory = new DirPickerCtrl (_panel);
310 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
312 table->Add (_directory, 1, wxEXPAND);
314 add_label_to_sizer (table, _panel, _("Default content type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
315 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
316 table->Add (_dcp_content_type);
318 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
319 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
320 table->Add (_dcp_audio_channels);
323 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
324 auto s = new wxBoxSizer (wxHORIZONTAL);
325 _j2k_bandwidth = new wxSpinCtrl (_panel);
326 s->Add (_j2k_bandwidth);
327 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
332 add_label_to_sizer (table, _panel, _("Default audio delay"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
333 auto s = new wxBoxSizer (wxHORIZONTAL);
334 _audio_delay = new wxSpinCtrl (_panel);
335 s->Add (_audio_delay);
336 add_label_to_sizer (s, _panel, _("ms"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
340 add_label_to_sizer (table, _panel, _("Default standard"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
341 _standard = new wxChoice (_panel, wxID_ANY);
342 table->Add (_standard);
344 _enable_audio_language = new CheckBox(_panel, _("Default audio language"));
345 table->Add(_enable_audio_language, 1, wxEXPAND | wxALIGN_CENTRE_VERTICAL);
346 _audio_language = new LanguageTagWidget(_panel, _("Default audio language to use for new DCPs"), Config::instance()->default_audio_language(), wxString("cmnr-Hant-"));
347 table->Add(_audio_language->sizer());
349 _enable_territory = new CheckBox(_panel, _("Default territory"));
350 table->Add(_enable_territory, 1, wxEXPAND | wxALIGN_CENTRE_VERTICAL);
351 _territory = new RegionSubtagWidget(_panel, _("Default territory to use for new DCPs"), Config::instance()->default_territory(), wxString("cmnr-Hant-"));
352 table->Add(_territory->sizer());
354 table->Add (_enable_metadata["facility"] = new CheckBox (_panel, _("Default facility")), 0, wxALIGN_CENTRE_VERTICAL);
355 table->Add (_metadata["facility"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
357 table->Add (_enable_metadata["studio"] = new CheckBox (_panel, _("Default studio")), 0, wxALIGN_CENTRE_VERTICAL);
358 table->Add (_metadata["studio"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
360 table->Add (_enable_metadata["chain"] = new CheckBox (_panel, _("Default chain")), 0, wxALIGN_CENTRE_VERTICAL);
361 table->Add (_metadata["chain"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
363 table->Add (_enable_metadata["distributor"] = new CheckBox (_panel, _("Default distributor")), 0, wxALIGN_CENTRE_VERTICAL);
364 table->Add (_metadata["distributor"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
366 add_label_to_sizer (table, _panel, _("Default KDM directory"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
367 #ifdef DCPOMATIC_USE_OWN_PICKER
368 _kdm_directory = new DirPickerCtrl (_panel);
370 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
372 table->Add (_kdm_directory, 1, wxEXPAND);
374 add_label_to_sizer (table, _panel, _("Default KDM type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
375 _kdm_type = new KDMChoice (_panel);
376 table->Add (_kdm_type, 1, wxEXPAND);
378 add_label_to_sizer (table, _panel, _("Default KDM duration"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
379 _kdm_duration = new wxSpinCtrl (_panel);
380 _kdm_duration_unit = new wxChoice (_panel, wxID_ANY);
381 auto kdm_duration_sizer = new wxBoxSizer (wxHORIZONTAL);
382 kdm_duration_sizer->Add (_kdm_duration, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
383 kdm_duration_sizer->Add (_kdm_duration_unit, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
384 table->Add (kdm_duration_sizer, 1, wxEXPAND);
386 table->Add (_use_isdcf_name_by_default = new CheckBox(_panel, _("Use ISDCF name by default")), 0, wxALIGN_CENTRE_VERTICAL);
388 _still_length->SetRange (1, 3600);
389 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
391 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
392 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
393 _kdm_type->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_type_changed, this));
394 _kdm_duration_unit->Append (_("days"));
395 _kdm_duration_unit->Append (_("weeks"));
396 _kdm_duration_unit->Append (_("months"));
397 _kdm_duration_unit->Append (_("years"));
399 _kdm_duration->Bind (wxEVT_SPINCTRL, boost::bind(&DefaultsPage::kdm_duration_changed, this));
400 _kdm_duration_unit->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_duration_changed, this));
402 _use_isdcf_name_by_default->bind(&DefaultsPage::use_isdcf_name_by_default_changed, this);
404 for (auto i: DCPContentType::all()) {
405 _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
408 setup_audio_channels_choice (_dcp_audio_channels, 2);
410 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
411 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
413 _j2k_bandwidth->SetRange (50, 250);
414 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
416 _audio_delay->SetRange (-1000, 1000);
417 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
419 _standard->Append (_("SMPTE"));
420 _standard->Append (_("Interop"));
421 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
423 for (auto const& i: _enable_metadata) {
424 i.second->bind(&DefaultsPage::metadata_changed, this);
427 for (auto const& i: _metadata) {
428 i.second->Bind (wxEVT_TEXT, boost::bind(&DefaultsPage::metadata_changed, this));
431 _enable_audio_language->bind(&DefaultsPage::enable_audio_language_toggled, this);
432 _audio_language->Changed.connect(boost::bind(&DefaultsPage::audio_language_changed, this));
434 _enable_territory->bind(&DefaultsPage::enable_territory_toggled, this);
435 _territory->Changed.connect(boost::bind(&DefaultsPage::territory_changed, this));
438 void config_changed () override
440 auto config = Config::instance ();
442 auto const ct = DCPContentType::all ();
443 for (size_t i = 0; i < ct.size(); ++i) {
444 if (ct[i] == config->default_dcp_content_type()) {
445 _dcp_content_type->SetSelection (i);
449 checked_set (_still_length, config->default_still_length ());
450 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
451 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
452 _kdm_type->set (config->default_kdm_type());
453 checked_set (_use_isdcf_name_by_default, config->use_isdcf_name_by_default());
454 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
455 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
456 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
457 checked_set (_audio_delay, config->default_audio_delay ());
458 checked_set (_standard, config->default_interop() ? 1 : 0);
459 auto dal = config->default_audio_language();
460 checked_set(_enable_audio_language, static_cast<bool>(dal));
461 checked_set(_audio_language, dal ? dal : boost::none);
462 auto dt = config->default_territory();
463 checked_set(_enable_territory, static_cast<bool>(dt));
464 checked_set(_territory, dt ? dt : boost::none);
466 auto metadata = config->default_metadata();
468 for (auto const& i: metadata) {
469 _enable_metadata[i.first]->SetValue(true);
470 checked_set (_metadata[i.first], i.second);
473 for (auto const& i: _enable_metadata) {
474 if (metadata.find(i.first) == metadata.end()) {
475 checked_set (i.second, false);
479 for (auto const& i: _metadata) {
480 if (metadata.find(i.first) == metadata.end()) {
481 checked_set (i.second, wxT(""));
485 checked_set (_kdm_duration, config->default_kdm_duration().duration);
486 switch (config->default_kdm_duration().unit) {
487 case RoughDuration::Unit::DAYS:
488 _kdm_duration->SetRange(1, 365);
489 checked_set (_kdm_duration_unit, 0);
491 case RoughDuration::Unit::WEEKS:
492 _kdm_duration->SetRange(1, 52);
493 checked_set (_kdm_duration_unit, 1);
495 case RoughDuration::Unit::MONTHS:
496 _kdm_duration->SetRange(1, 12);
497 checked_set (_kdm_duration_unit, 2);
499 case RoughDuration::Unit::YEARS:
500 _kdm_duration->SetRange(1, 40);
501 checked_set (_kdm_duration_unit, 3);
505 setup_sensitivity ();
508 void kdm_duration_changed ()
510 auto config = Config::instance();
511 auto duration = _kdm_duration->GetValue();
512 RoughDuration::Unit unit = RoughDuration::Unit::DAYS;
513 switch (_kdm_duration_unit->GetSelection()) {
515 unit = RoughDuration::Unit::DAYS;
518 unit = RoughDuration::Unit::WEEKS;
521 unit = RoughDuration::Unit::MONTHS;
524 unit = RoughDuration::Unit::YEARS;
527 config->set_default_kdm_duration (RoughDuration(duration, unit));
530 void j2k_bandwidth_changed ()
532 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
535 void audio_delay_changed ()
537 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
540 void dcp_audio_channels_changed ()
542 int const s = _dcp_audio_channels->GetSelection ();
543 if (s != wxNOT_FOUND) {
544 Config::instance()->set_default_dcp_audio_channels (
545 locale_convert<int>(string_client_data(_dcp_audio_channels->GetClientObject(s)))
550 void directory_changed ()
552 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
555 void kdm_directory_changed ()
557 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
560 void kdm_type_changed ()
562 Config::instance()->set_default_kdm_type(_kdm_type->get());
565 void use_isdcf_name_by_default_changed ()
567 Config::instance()->set_use_isdcf_name_by_default (_use_isdcf_name_by_default->GetValue());
570 void still_length_changed ()
572 Config::instance()->set_default_still_length (_still_length->GetValue ());
575 void dcp_content_type_changed ()
577 auto ct = DCPContentType::all ();
578 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
581 void standard_changed ()
583 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
586 void metadata_changed ()
588 map<string, string> metadata;
589 for (auto const& i: _enable_metadata) {
590 if (i.second->GetValue()) {
591 metadata[i.first] = wx_to_std(_metadata[i.first]->GetValue());
594 Config::instance()->set_default_metadata (metadata);
595 setup_sensitivity ();
598 void enable_audio_language_toggled()
601 audio_language_changed();
604 void audio_language_changed()
606 if (_enable_audio_language->get()) {
607 Config::instance()->set_default_audio_language(_audio_language->get().get_value_or(dcp::LanguageTag("en-US")));
609 Config::instance()->unset_default_audio_language();
613 void enable_territory_toggled()
619 void territory_changed()
621 if (_enable_territory->get()) {
622 Config::instance()->set_default_territory(_territory->get().get_value_or(dcp::LanguageTag::RegionSubtag("US")));
624 Config::instance()->unset_default_territory();
628 void setup_sensitivity ()
630 _audio_language->enable(_enable_audio_language->get());
631 _territory->enable(_enable_territory->get());
632 for (auto const& i: _enable_metadata) {
633 _metadata[i.first]->Enable(i.second->GetValue());
637 wxSpinCtrl* _j2k_bandwidth;
638 wxSpinCtrl* _audio_delay;
639 wxSpinCtrl* _still_length;
640 #ifdef DCPOMATIC_USE_OWN_PICKER
641 DirPickerCtrl* _directory;
642 DirPickerCtrl* _kdm_directory;
644 wxDirPickerCtrl* _directory;
645 wxDirPickerCtrl* _kdm_directory;
647 KDMChoice* _kdm_type;
648 wxSpinCtrl* _kdm_duration;
649 wxChoice* _kdm_duration_unit;
650 CheckBox* _use_isdcf_name_by_default;
651 wxChoice* _dcp_content_type;
652 wxChoice* _dcp_audio_channels;
654 CheckBox* _enable_audio_language;
655 LanguageTagWidget* _audio_language;
656 CheckBox* _enable_territory;
657 RegionSubtagWidget* _territory;
658 map<string, CheckBox*> _enable_metadata;
659 map<string, wxTextCtrl*> _metadata;
663 class EncodingServersPage : public Page
666 EncodingServersPage (wxSize panel_size, int border)
667 : Page (panel_size, border)
670 wxString GetName () const override
676 wxBitmap GetLargeIcon () const override
678 return wxBitmap(icon_path("servers"), wxBITMAP_TYPE_PNG);
683 void setup () override
685 _use_any_servers = new CheckBox (_panel, _("Search network for servers"));
686 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
688 vector<EditableListColumn> columns;
689 columns.push_back (EditableListColumn(_("IP address / host name")));
690 _servers_list = new EditableList<string, ServerDialog> (
693 boost::bind (&Config::servers, Config::instance()),
694 boost::bind (&Config::set_servers, Config::instance(), _1),
695 boost::bind (&EncodingServersPage::server_column, this, _1),
696 EditableListTitle::INVISIBLE,
697 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
700 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
702 _use_any_servers->bind(&EncodingServersPage::use_any_servers_changed, this);
705 void config_changed () override
707 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
708 _servers_list->refresh ();
711 void use_any_servers_changed ()
713 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
716 string server_column (string s)
721 CheckBox* _use_any_servers;
722 EditableList<string, ServerDialog>* _servers_list;
726 class TMSPage : public Page
729 TMSPage (wxSize panel_size, int border)
730 : Page (panel_size, border)
733 wxString GetName () const override
739 wxBitmap GetLargeIcon () const override
741 return wxBitmap(icon_path("tms"), wxBITMAP_TYPE_PNG);
746 void setup () override
748 _upload = new CheckBox (_panel, _("Upload DCP to TMS after creation"));
749 _panel->GetSizer()->Add (_upload, 0, wxALL | wxEXPAND, _border);
751 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
752 table->AddGrowableCol (1, 1);
753 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
755 add_label_to_sizer (table, _panel, _("Protocol"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
756 _tms_protocol = new wxChoice (_panel, wxID_ANY);
757 table->Add (_tms_protocol, 1, wxEXPAND);
759 _tms_passive = new CheckBox(_panel, _("Passive mode"));
760 table->Add(_tms_passive, 1, wxEXPAND);
763 add_label_to_sizer (table, _panel, _("IP address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
764 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
765 table->Add (_tms_ip, 1, wxEXPAND);
767 add_label_to_sizer (table, _panel, _("Target path"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
768 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
769 table->Add (_tms_path, 1, wxEXPAND);
771 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
772 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
773 table->Add (_tms_user, 1, wxEXPAND);
775 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
776 _tms_password = new PasswordEntry (_panel);
777 table->Add (_tms_password->get_panel(), 1, wxEXPAND);
779 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
780 _tms_protocol->Append (_("FTP (for Dolby)"));
782 _upload->bind(&TMSPage::upload_changed, this);
783 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
784 _tms_passive->bind(&TMSPage::tms_passive_changed, this);
786 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
787 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
788 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
789 _tms_password->Changed.connect (boost::bind (&TMSPage::tms_password_changed, this));
792 void config_changed () override
794 auto config = Config::instance ();
796 checked_set (_upload, config->upload_after_make_dcp());
797 checked_set (_tms_protocol, static_cast<int>(config->tms_protocol()));
798 checked_set(_tms_passive, config->tms_protocol() == FileTransferProtocol::FTP && config->tms_passive());
799 checked_set (_tms_ip, config->tms_ip ());
800 checked_set (_tms_path, config->tms_path ());
801 checked_set (_tms_user, config->tms_user ());
802 checked_set (_tms_password, config->tms_password ());
804 _tms_passive->Enable(config->tms_protocol() == FileTransferProtocol::FTP);
807 void upload_changed ()
809 Config::instance()->set_upload_after_make_dcp (_upload->GetValue());
812 void tms_protocol_changed ()
814 Config::instance()->set_tms_protocol(static_cast<FileTransferProtocol>(_tms_protocol->GetSelection()));
817 void tms_passive_changed()
819 Config::instance()->set_tms_passive(_tms_passive->get());
822 void tms_ip_changed ()
824 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
827 void tms_path_changed ()
829 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
832 void tms_user_changed ()
834 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
837 void tms_password_changed ()
839 Config::instance()->set_tms_password (_tms_password->get());
843 CheckBox* _tms_passive;
844 wxChoice* _tms_protocol;
846 wxTextCtrl* _tms_path;
847 wxTextCtrl* _tms_user;
848 PasswordEntry* _tms_password;
852 class EmailPage : public Page
855 EmailPage (wxSize panel_size, int border)
856 : Page (panel_size, border)
859 wxString GetName () const override
865 wxBitmap GetLargeIcon () const override
867 return wxBitmap(icon_path("email"), wxBITMAP_TYPE_PNG);
872 void setup () override
874 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
875 table->AddGrowableCol (1, 1);
876 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
878 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
880 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
881 _server = new wxTextCtrl (_panel, wxID_ANY);
882 s->Add (_server, 1, wxEXPAND | wxALL);
883 add_label_to_sizer (s, _panel, _("port"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
884 _port = new wxSpinCtrl (_panel, wxID_ANY);
885 _port->SetRange (0, 65535);
887 add_label_to_sizer (s, _panel, _("protocol"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
888 _protocol = new wxChoice (_panel, wxID_ANY);
889 /* Make sure this matches the switches in config_changed and port_changed below */
890 _protocol->Append (_("Auto"));
891 _protocol->Append (_("Plain"));
892 _protocol->Append (_("STARTTLS"));
893 _protocol->Append (_("SSL"));
894 s->Add (_protocol, 1, wxALIGN_CENTER_VERTICAL);
895 table->Add (s, 1, wxEXPAND | wxALL);
898 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
899 _user = new wxTextCtrl (_panel, wxID_ANY);
900 table->Add (_user, 1, wxEXPAND | wxALL);
902 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
903 _password = new PasswordEntry (_panel);
904 table->Add (_password->get_panel(), 1, wxEXPAND | wxALL);
906 table->AddSpacer (0);
907 _send_test_email = new Button (_panel, _("Send test email..."));
908 table->Add (_send_test_email);
910 _server->Bind (wxEVT_TEXT, boost::bind(&EmailPage::server_changed, this));
911 _port->Bind (wxEVT_SPINCTRL, boost::bind(&EmailPage::port_changed, this));
912 _protocol->Bind (wxEVT_CHOICE, boost::bind(&EmailPage::protocol_changed, this));
913 _user->Bind (wxEVT_TEXT, boost::bind(&EmailPage::user_changed, this));
914 _password->Changed.connect (boost::bind(&EmailPage::password_changed, this));
915 _send_test_email->Bind (wxEVT_BUTTON, boost::bind(&EmailPage::send_test_email_clicked, this));
918 void config_changed () override
920 auto config = Config::instance ();
922 checked_set (_server, config->mail_server());
923 checked_set (_port, config->mail_port());
924 switch (config->mail_protocol()) {
925 case EmailProtocol::AUTO:
926 checked_set (_protocol, 0);
928 case EmailProtocol::PLAIN:
929 checked_set (_protocol, 1);
931 case EmailProtocol::STARTTLS:
932 checked_set (_protocol, 2);
934 case EmailProtocol::SSL:
935 checked_set (_protocol, 3);
938 checked_set (_user, config->mail_user());
939 checked_set (_password, config->mail_password());
942 void server_changed ()
944 Config::instance()->set_mail_server(wx_to_std(_server->GetValue()));
949 Config::instance()->set_mail_port(_port->GetValue());
952 void protocol_changed ()
954 switch (_protocol->GetSelection()) {
956 Config::instance()->set_mail_protocol(EmailProtocol::AUTO);
959 Config::instance()->set_mail_protocol(EmailProtocol::PLAIN);
962 Config::instance()->set_mail_protocol(EmailProtocol::STARTTLS);
965 Config::instance()->set_mail_protocol(EmailProtocol::SSL);
972 Config::instance()->set_mail_user (wx_to_std (_user->GetValue ()));
975 void password_changed ()
977 Config::instance()->set_mail_password(_password->get());
980 void send_test_email_clicked ()
982 SendTestEmailDialog dialog(_panel);
983 if (dialog.ShowModal() != wxID_OK) {
988 wx_to_std(dialog.from()),
989 { wx_to_std(dialog.to()) },
990 wx_to_std(variant::wx::insert_dcpomatic(_("%s test email"))),
991 wx_to_std(variant::wx::insert_dcpomatic(_("This is a test email from %s.")))
993 auto config = Config::instance();
995 email.send(config->mail_server(), config->mail_port(), config->mail_protocol(), config->mail_user(), config->mail_password());
996 } catch (NetworkError& e) {
997 error_dialog(_panel, std_to_wx(e.summary()), std_to_wx(e.detail().get_value_or("")));
999 } catch (std::exception& e) {
1000 error_dialog(_panel, _("Test email sending failed."), std_to_wx(e.what()));
1003 error_dialog(_panel, _("Test email sending failed."));
1006 message_dialog(_panel, _("Test email sent."));
1009 wxTextCtrl* _server;
1011 wxChoice* _protocol;
1013 PasswordEntry* _password;
1014 Button* _send_test_email;
1018 class KDMEmailPage : public Page
1022 KDMEmailPage (wxSize panel_size, int border)
1023 #ifdef DCPOMATIC_OSX
1024 /* We have to force both width and height of this one */
1025 : Page (wxSize (panel_size.GetWidth(), 128), border)
1027 : Page (panel_size, border)
1031 wxString GetName () const override
1033 return _("KDM Email");
1036 #ifdef DCPOMATIC_OSX
1037 wxBitmap GetLargeIcon () const override
1039 return wxBitmap(icon_path("kdm_email"), wxBITMAP_TYPE_PNG);
1044 void setup () override
1046 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1047 table->AddGrowableCol (1, 1);
1048 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1050 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1051 _subject = new wxTextCtrl (_panel, wxID_ANY);
1052 table->Add (_subject, 1, wxEXPAND | wxALL);
1054 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1055 _from = new wxTextCtrl (_panel, wxID_ANY);
1056 table->Add (_from, 1, wxEXPAND | wxALL);
1058 vector<EditableListColumn> columns;
1059 columns.push_back (EditableListColumn(_("Address")));
1060 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1061 _cc = new EditableList<string, EmailDialog> (
1064 bind (&Config::kdm_cc, Config::instance()),
1065 bind (&Config::set_kdm_cc, Config::instance(), _1),
1066 [] (string s, int) {
1069 EditableListTitle::VISIBLE,
1070 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
1072 table->Add (_cc, 1, wxEXPAND | wxALL);
1074 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1075 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1076 table->Add (_bcc, 1, wxEXPAND | wxALL);
1078 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1079 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1081 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1082 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1086 _subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1087 _from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1088 _bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1089 _email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1090 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_email, this));
1093 void config_changed () override
1095 auto config = Config::instance ();
1097 checked_set (_subject, config->kdm_subject ());
1098 checked_set (_from, config->kdm_from ());
1099 checked_set (_bcc, config->kdm_bcc ());
1100 checked_set (_email, Config::instance()->kdm_email ());
1103 void kdm_subject_changed ()
1105 Config::instance()->set_kdm_subject (wx_to_std (_subject->GetValue ()));
1108 void kdm_from_changed ()
1110 Config::instance()->set_kdm_from (wx_to_std (_from->GetValue ()));
1113 void kdm_bcc_changed ()
1115 Config::instance()->set_kdm_bcc (wx_to_std (_bcc->GetValue ()));
1118 void kdm_email_changed ()
1120 if (_email->GetValue().IsEmpty ()) {
1121 /* Sometimes we get sent an erroneous notification that the email
1122 is empty; I don't know why.
1126 Config::instance()->set_kdm_email (wx_to_std (_email->GetValue ()));
1131 Config::instance()->reset_kdm_email ();
1132 checked_set (_email, Config::instance()->kdm_email ());
1135 wxTextCtrl* _subject;
1137 EditableList<string, EmailDialog>* _cc;
1140 wxButton* _reset_email;
1144 class NotificationsPage : public Page
1147 NotificationsPage (wxSize panel_size, int border)
1148 #ifdef DCPOMATIC_OSX
1149 /* We have to force both width and height of this one */
1150 : Page (wxSize (panel_size.GetWidth(), 128), border)
1152 : Page (panel_size, border)
1156 wxString GetName () const override
1158 return _("Notifications");
1161 #ifdef DCPOMATIC_OSX
1162 wxBitmap GetLargeIcon () const override
1164 return wxBitmap(icon_path("notifications"), wxBITMAP_TYPE_PNG);
1169 void setup () override
1171 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1172 table->AddGrowableCol (1, 1);
1173 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1175 _enable_message_box = new CheckBox (_panel, _("Message box"));
1176 table->Add (_enable_message_box, 1, wxEXPAND | wxALL);
1177 table->AddSpacer (0);
1179 _enable_email = new CheckBox (_panel, _("Email"));
1180 table->Add (_enable_email, 1, wxEXPAND | wxALL);
1181 table->AddSpacer (0);
1183 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1184 _subject = new wxTextCtrl (_panel, wxID_ANY);
1185 table->Add (_subject, 1, wxEXPAND | wxALL);
1187 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1188 _from = new wxTextCtrl (_panel, wxID_ANY);
1189 table->Add (_from, 1, wxEXPAND | wxALL);
1191 add_label_to_sizer (table, _panel, _("To address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1192 _to = new wxTextCtrl (_panel, wxID_ANY);
1193 table->Add (_to, 1, wxEXPAND | wxALL);
1195 vector<EditableListColumn> columns;
1196 columns.push_back (EditableListColumn(_("Address")));
1197 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1198 _cc = new EditableList<string, EmailDialog> (
1201 bind (&Config::notification_cc, Config::instance()),
1202 bind (&Config::set_notification_cc, Config::instance(), _1),
1203 [] (string s, int) {
1206 EditableListTitle::VISIBLE,
1207 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
1209 table->Add (_cc, 1, wxEXPAND | wxALL);
1211 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1212 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1213 table->Add (_bcc, 1, wxEXPAND | wxALL);
1215 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1216 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1218 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1219 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1223 _enable_message_box->bind(&NotificationsPage::type_changed, this, _enable_message_box, Config::MESSAGE_BOX);
1224 _enable_email->bind(&NotificationsPage::type_changed, this, _enable_email, Config::EMAIL);
1226 _subject->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_subject_changed, this));
1227 _from->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_from_changed, this));
1228 _to->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_to_changed, this));
1229 _bcc->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_bcc_changed, this));
1230 _email->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_email_changed, this));
1231 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&NotificationsPage::reset_email, this));
1233 setup_sensitivity ();
1236 void setup_sensitivity ()
1238 bool const s = _enable_email->GetValue();
1239 _subject->Enable(s);
1245 _reset_email->Enable(s);
1248 void config_changed () override
1250 auto config = Config::instance ();
1252 checked_set (_enable_message_box, config->notification(Config::MESSAGE_BOX));
1253 checked_set (_enable_email, config->notification(Config::EMAIL));
1254 checked_set (_subject, config->notification_subject ());
1255 checked_set (_from, config->notification_from ());
1256 checked_set (_to, config->notification_to ());
1257 checked_set (_bcc, config->notification_bcc ());
1258 checked_set (_email, Config::instance()->notification_email ());
1260 setup_sensitivity ();
1263 void notification_subject_changed ()
1265 Config::instance()->set_notification_subject(wx_to_std(_subject->GetValue()));
1268 void notification_from_changed ()
1270 Config::instance()->set_notification_from(wx_to_std(_from->GetValue()));
1273 void notification_to_changed ()
1275 Config::instance()->set_notification_to(wx_to_std(_to->GetValue()));
1278 void notification_bcc_changed ()
1280 Config::instance()->set_notification_bcc(wx_to_std(_bcc->GetValue()));
1283 void notification_email_changed ()
1285 if (_email->GetValue().IsEmpty()) {
1286 /* Sometimes we get sent an erroneous notification that the email
1287 is empty; I don't know why.
1291 Config::instance()->set_notification_email(wx_to_std(_email->GetValue()));
1296 Config::instance()->reset_notification_email();
1297 checked_set (_email, Config::instance()->notification_email());
1300 void type_changed (CheckBox* b, Config::Notification n)
1302 Config::instance()->set_notification(n, b->GetValue());
1303 setup_sensitivity ();
1306 CheckBox* _enable_message_box;
1307 CheckBox* _enable_email;
1309 wxTextCtrl* _subject;
1312 EditableList<string, EmailDialog>* _cc;
1315 wxButton* _reset_email;
1319 class CoverSheetPage : public Page
1323 CoverSheetPage (wxSize panel_size, int border)
1324 #ifdef DCPOMATIC_OSX
1325 /* We have to force both width and height of this one */
1326 : Page (wxSize (panel_size.GetWidth(), 128), border)
1328 : Page (panel_size, border)
1332 wxString GetName () const override
1334 return _("Cover Sheet");
1337 #ifdef DCPOMATIC_OSX
1338 wxBitmap GetLargeIcon () const override
1340 return wxBitmap(icon_path("cover_sheet"), wxBITMAP_TYPE_PNG);
1345 void setup () override
1347 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1348 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
1350 _reset_cover_sheet = new Button (_panel, _("Reset to default text"));
1351 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
1353 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
1354 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
1357 void config_changed () override
1359 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1362 void cover_sheet_changed ()
1364 if (_cover_sheet->GetValue().IsEmpty ()) {
1365 /* Sometimes we get sent an erroneous notification that the cover sheet
1366 is empty; I don't know why.
1370 Config::instance()->set_cover_sheet(wx_to_std(_cover_sheet->GetValue()));
1373 void reset_cover_sheet ()
1375 Config::instance()->reset_cover_sheet();
1376 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1379 wxTextCtrl* _cover_sheet;
1380 wxButton* _reset_cover_sheet;
1384 class IdentifiersPage : public Page
1387 IdentifiersPage (wxSize panel_size, int border)
1388 : Page (panel_size, border)
1391 wxString GetName () const override
1393 return _("Identifiers");
1396 #ifdef DCPOMATIC_OSX
1397 wxBitmap GetLargeIcon () const override
1399 return wxBitmap(icon_path("identifiers"), wxBITMAP_TYPE_PNG);
1404 void setup () override
1406 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1407 table->AddGrowableCol (1, 1);
1409 add_label_to_sizer (table, _panel, _("Issuer"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1410 _issuer = new wxTextCtrl (_panel, wxID_ANY);
1411 _issuer->SetToolTip(
1412 variant::wx::insert_dcpomatic(
1413 _("This will be written to the DCP's XML files as the <Issuer>. If it is blank, a default value mentioning %s will be used.")
1415 table->Add (_issuer, 1, wxALL | wxEXPAND);
1417 add_label_to_sizer (table, _panel, _("Creator"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1418 _creator = new wxTextCtrl (_panel, wxID_ANY);
1419 _creator->SetToolTip(
1420 variant::wx::insert_dcpomatic(
1421 _("This will be written to the DCP's XML files as the <Creator>. If it is blank, a default value mentioning %s will be used.")
1423 table->Add (_creator, 1, wxALL | wxEXPAND);
1425 add_label_to_sizer (table, _panel, _("Company name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1426 _company_name = new wxTextCtrl (_panel, wxID_ANY);
1427 _company_name->SetToolTip(
1428 variant::wx::insert_dcpomatic(
1429 _("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 %s library) will be used.")
1431 table->Add (_company_name, 1, wxALL | wxEXPAND);
1433 add_label_to_sizer (table, _panel, _("Product name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1434 _product_name = new wxTextCtrl (_panel, wxID_ANY);
1435 _product_name->SetToolTip(
1436 variant::wx::insert_dcpomatic(
1437 _("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 %s library) will be used.")
1439 table->Add (_product_name, 1, wxALL | wxEXPAND);
1441 add_label_to_sizer (table, _panel, _("Product version"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1442 _product_version = new wxTextCtrl (_panel, wxID_ANY);
1443 _product_version->SetToolTip(
1444 variant::wx::insert_dcpomatic(
1445 _("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 %s library) will be used.")
1447 table->Add (_product_version, 1, wxALL | wxEXPAND);
1449 add_label_to_sizer (table, _panel, _("JPEG2000 comment"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1450 _j2k_comment = new wxTextCtrl (_panel, wxID_ANY);
1451 _j2k_comment->SetToolTip(
1452 variant::wx::insert_dcpomatic(
1453 _("This will be written to the DCP's JPEG2000 data as a comment. If it is blank, a default value mentioning libdcp (an internal %s library) will be used.")
1455 table->Add (_j2k_comment, 1, wxALL | wxEXPAND);
1457 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1459 _issuer->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::issuer_changed, this));
1460 _creator->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::creator_changed, this));
1461 _company_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::company_name_changed, this));
1462 _product_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_name_changed, this));
1463 _product_version->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_version_changed, this));
1464 _j2k_comment->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::j2k_comment_changed, this));
1467 void config_changed () override
1469 auto config = Config::instance ();
1470 checked_set (_issuer, config->dcp_issuer ());
1471 checked_set (_creator, config->dcp_creator ());
1472 checked_set (_company_name, config->dcp_company_name ());
1473 checked_set (_product_name, config->dcp_product_name ());
1474 checked_set (_product_version, config->dcp_product_version ());
1475 checked_set (_j2k_comment, config->dcp_j2k_comment ());
1478 void issuer_changed ()
1480 Config::instance()->set_dcp_issuer(wx_to_std(_issuer->GetValue()));
1483 void creator_changed ()
1485 Config::instance()->set_dcp_creator(wx_to_std(_creator->GetValue()));
1488 void company_name_changed ()
1490 Config::instance()->set_dcp_company_name(wx_to_std(_company_name->GetValue()));
1493 void product_name_changed ()
1495 Config::instance()->set_dcp_product_name(wx_to_std(_product_name->GetValue()));
1498 void product_version_changed ()
1500 Config::instance()->set_dcp_product_version(wx_to_std(_product_version->GetValue()));
1503 void j2k_comment_changed ()
1505 Config::instance()->set_dcp_j2k_comment (wx_to_std(_j2k_comment->GetValue()));
1508 wxTextCtrl* _issuer;
1509 wxTextCtrl* _creator;
1510 wxTextCtrl* _company_name;
1511 wxTextCtrl* _product_name;
1512 wxTextCtrl* _product_version;
1513 wxTextCtrl* _j2k_comment;
1517 class NonStandardPage : public Page
1520 NonStandardPage(wxSize panel_size, int border)
1521 : Page(panel_size, border)
1524 wxString GetName() const override
1526 return _("Non-standard");
1529 #ifdef DCPOMATIC_OSX
1530 wxBitmap GetLargeIcon() const override
1532 return wxBitmap(icon_path("non_standard"), wxBITMAP_TYPE_PNG);
1537 void setup() override
1539 auto table = new wxFlexGridSizer(2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1540 table->AddGrowableCol(1, 1);
1541 _panel->GetSizer()->Add(table, 1, wxALL | wxEXPAND, _border);
1544 add_label_to_sizer(table, _panel, _("Maximum JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1545 auto s = new wxBoxSizer(wxHORIZONTAL);
1546 _maximum_j2k_bandwidth = new wxSpinCtrl(_panel);
1547 s->Add(_maximum_j2k_bandwidth, 1);
1548 add_label_to_sizer(s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxALIGN_CENTRE_VERTICAL);
1552 auto checkbox = [this, table](wxString name, CheckBox*& variable) {
1553 variable = new CheckBox(_panel, name);
1554 table->Add(variable, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1555 table->AddSpacer(0);
1558 checkbox(_("Allow any DCP frame rate"), _allow_any_dcp_frame_rate);
1560 _allow_any_container = new CheckBox(_panel, _("Allow full-frame and non-standard container ratios"));
1561 table->Add(_allow_any_container, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1562 auto restart = new StaticText(_panel, variant::wx::insert_dcpomatic(_("(restart %s to see all ratios)")));
1563 auto font = restart->GetFont();
1564 font.SetStyle(wxFONTSTYLE_ITALIC);
1565 font.SetPointSize(font.GetPointSize() - 1);
1566 restart->SetFont(font);
1567 table->Add(restart, 1, wxALIGN_CENTRE_VERTICAL | wxBOTTOM, DCPOMATIC_CHECKBOX_BOTTOM_PAD);
1568 restart->SetFont(font);
1570 checkbox(_("Allow creation of DCPs with 96kHz audio"), _allow_96khz_audio);
1571 checkbox(_("Allow mapping to all audio channels"), _use_all_audio_channels);
1572 checkbox(_("Allow use of SMPTE Bv2.0"), _allow_smpte_bv20);
1575 add_label_to_sizer(table, _panel, _("ISDCF name part length"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1576 auto s = new wxBoxSizer(wxHORIZONTAL);
1577 _isdcf_name_part_length = new wxSpinCtrl(_panel);
1578 s->Add(_isdcf_name_part_length, 1);
1582 _maximum_j2k_bandwidth->SetRange(1, 1000);
1583 _maximum_j2k_bandwidth->Bind(wxEVT_SPINCTRL, boost::bind(&NonStandardPage::maximum_j2k_bandwidth_changed, this));
1584 _allow_any_dcp_frame_rate->bind(&NonStandardPage::allow_any_dcp_frame_rate_changed, this);
1585 _allow_any_container->bind(&NonStandardPage::allow_any_container_changed, this);
1586 _allow_96khz_audio->bind(&NonStandardPage::allow_96khz_audio_changed, this);
1587 _use_all_audio_channels->bind(&NonStandardPage::use_all_channels_changed, this);
1588 _allow_smpte_bv20->bind(&NonStandardPage::allow_smpte_bv20_changed, this);
1589 _isdcf_name_part_length->SetRange(1, 256);
1590 _isdcf_name_part_length->Bind(wxEVT_SPINCTRL, boost::bind(&NonStandardPage::isdcf_name_part_length_changed, this));
1593 void config_changed() override
1595 auto config = Config::instance();
1597 checked_set(_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1598 checked_set(_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate());
1599 checked_set(_allow_any_container, config->allow_any_container());
1600 checked_set(_allow_96khz_audio, config->allow_96khz_audio());
1601 checked_set(_use_all_audio_channels, config->use_all_audio_channels());
1602 checked_set(_allow_smpte_bv20, config->allow_smpte_bv20());
1603 checked_set(_isdcf_name_part_length, config->isdcf_name_part_length());
1606 void maximum_j2k_bandwidth_changed()
1608 Config::instance()->set_maximum_j2k_bandwidth(_maximum_j2k_bandwidth->GetValue() * 1000000);
1611 void allow_any_dcp_frame_rate_changed()
1613 Config::instance()->set_allow_any_dcp_frame_rate(_allow_any_dcp_frame_rate->GetValue());
1616 void allow_any_container_changed()
1618 Config::instance()->set_allow_any_container(_allow_any_container->GetValue());
1621 void allow_96khz_audio_changed()
1623 Config::instance()->set_allow_96hhz_audio(_allow_96khz_audio->GetValue());
1626 void use_all_channels_changed()
1628 Config::instance()->set_use_all_audio_channels(_use_all_audio_channels->GetValue());
1631 void allow_smpte_bv20_changed()
1633 Config::instance()->set_allow_smpte_bv20(_allow_smpte_bv20->GetValue());
1636 void isdcf_name_part_length_changed()
1638 Config::instance()->set_isdcf_name_part_length(_isdcf_name_part_length->GetValue());
1641 wxSpinCtrl* _maximum_j2k_bandwidth = nullptr;
1642 CheckBox* _allow_any_dcp_frame_rate = nullptr;
1643 CheckBox* _allow_any_container = nullptr;
1644 CheckBox* _allow_96khz_audio = nullptr;
1645 CheckBox* _use_all_audio_channels = nullptr;
1646 CheckBox* _allow_smpte_bv20 = nullptr;
1647 wxSpinCtrl* _isdcf_name_part_length = nullptr;
1652 /** @class AdvancedPage
1653 * @brief Advanced page of the preferences dialog.
1655 class AdvancedPage : public Page
1658 AdvancedPage (wxSize panel_size, int border)
1659 : Page (panel_size, border)
1662 wxString GetName () const override
1664 return _("Advanced");
1667 #ifdef DCPOMATIC_OSX
1668 wxBitmap GetLargeIcon () const override
1670 return wxBitmap(icon_path("advanced"), wxBITMAP_TYPE_PNG);
1675 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1677 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1679 flags |= wxALIGN_RIGHT;
1682 wxStaticText* m = new StaticText (parent, text);
1683 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1686 void setup () override
1688 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1689 table->AddGrowableCol (1, 1);
1690 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1692 add_label_to_sizer (table, _panel, _("Video display mode"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1693 _video_display_mode = new wxChoice (_panel, wxID_ANY);
1694 table->Add (_video_display_mode);
1696 auto restart = add_label_to_sizer(table, _panel, variant::wx::insert_dcpomatic(_("(restart %s to change display mode)")), false);
1697 auto font = restart->GetFont();
1698 font.SetStyle (wxFONTSTYLE_ITALIC);
1699 font.SetPointSize (font.GetPointSize() - 1);
1700 restart->SetFont (font);
1701 table->AddSpacer (0);
1703 _show_experimental_audio_processors = new CheckBox (_panel, _("Show experimental audio processors"));
1704 table->Add (_show_experimental_audio_processors, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1705 table->AddSpacer (0);
1707 _only_servers_encode = new CheckBox (_panel, _("Only servers encode"));
1708 table->Add (_only_servers_encode, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1709 table->AddSpacer (0);
1712 add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1713 auto s = new wxBoxSizer (wxHORIZONTAL);
1714 _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
1715 s->Add (_frames_in_memory_multiplier, 1);
1720 auto format = create_label (_panel, _("DCP metadata 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 (cpl/pkl)"));
1730 dcp::NameFormat::Map examples;
1731 examples['t'] = "cpl";
1732 _dcp_metadata_filename_format = new NameFormatEditor (
1733 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1735 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1739 auto format = create_label (_panel, _("DCP asset filename format"), true);
1740 #ifdef DCPOMATIC_OSX
1741 auto align = new wxBoxSizer (wxHORIZONTAL);
1742 align->Add (format, 0, wxTOP, 2);
1743 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1745 table->Add (format, 0, wxTOP | wxLEFT | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1747 dcp::NameFormat::Map titles;
1748 titles['t'] = wx_to_std (_("type (j2c/pcm/sub)"));
1749 titles['r'] = wx_to_std (_("reel number"));
1750 titles['n'] = wx_to_std (_("number of reels"));
1751 titles['c'] = wx_to_std (_("content filename"));
1752 dcp::NameFormat::Map examples;
1753 examples['t'] = "j2c";
1754 examples['r'] = "1";
1755 examples['n'] = "4";
1756 examples['c'] = "myfile.mp4";
1757 _dcp_asset_filename_format = new NameFormatEditor (
1758 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1760 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1764 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1765 auto t = new wxFlexGridSizer (2);
1766 _log_general = new CheckBox (_panel, _("General"));
1767 t->Add (_log_general, 1, wxEXPAND | wxALL);
1768 _log_warning = new CheckBox (_panel, _("Warnings"));
1769 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1770 _log_error = new CheckBox (_panel, _("Errors"));
1771 t->Add (_log_error, 1, wxEXPAND | wxALL);
1772 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1773 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
1774 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1775 _log_debug_threed = new CheckBox (_panel, _("Debug: 3D"));
1776 t->Add (_log_debug_threed, 1, wxEXPAND | wxALL);
1777 _log_debug_encode = new CheckBox (_panel, _("Debug: encode"));
1778 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1779 _log_debug_email = new CheckBox (_panel, _("Debug: email sending"));
1780 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1781 _log_debug_video_view = new CheckBox (_panel, _("Debug: video view"));
1782 t->Add (_log_debug_video_view, 1, wxEXPAND | wxALL);
1783 _log_debug_player = new CheckBox (_panel, _("Debug: player"));
1784 t->Add (_log_debug_player, 1, wxEXPAND | wxALL);
1785 _log_debug_audio_analysis = new CheckBox (_panel, _("Debug: audio analysis"));
1786 t->Add (_log_debug_audio_analysis, 1, wxEXPAND | wxALL);
1787 table->Add (t, 0, wxALL, 6);
1790 #ifdef DCPOMATIC_WINDOWS
1791 _win32_console = new CheckBox (_panel, _("Open console window"));
1792 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1793 table->AddSpacer (0);
1796 _video_display_mode->Append (_("Simple (safer)"));
1797 #if wxCHECK_VERSION(3, 1, 0)
1798 _video_display_mode->Append (_("OpenGL (faster)"));
1800 _video_display_mode->Bind (wxEVT_CHOICE, boost::bind(&AdvancedPage::video_display_mode_changed, this));
1801 _show_experimental_audio_processors->bind(&AdvancedPage::show_experimental_audio_processors_changed, this);
1802 _only_servers_encode->bind(&AdvancedPage::only_servers_encode_changed, this);
1803 _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
1804 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1805 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1806 _log_general->bind(&AdvancedPage::log_changed, this);
1807 _log_warning->bind(&AdvancedPage::log_changed, this);
1808 _log_error->bind(&AdvancedPage::log_changed, this);
1809 _log_timing->bind(&AdvancedPage::log_changed, this);
1810 _log_debug_threed->bind(&AdvancedPage::log_changed, this);
1811 _log_debug_encode->bind(&AdvancedPage::log_changed, this);
1812 _log_debug_email->bind(&AdvancedPage::log_changed, this);
1813 _log_debug_video_view->bind(&AdvancedPage::log_changed, this);
1814 _log_debug_player->bind(&AdvancedPage::log_changed, this);
1815 _log_debug_audio_analysis->bind(&AdvancedPage::log_changed, this);
1816 #ifdef DCPOMATIC_WINDOWS
1817 _win32_console->bind(&AdvancedPage::win32_console_changed, this);
1821 void config_changed () override
1823 auto config = Config::instance ();
1825 switch (config->video_view_type()) {
1826 case Config::VIDEO_VIEW_SIMPLE:
1827 checked_set (_video_display_mode, 0);
1829 case Config::VIDEO_VIEW_OPENGL:
1830 checked_set (_video_display_mode, 1);
1833 checked_set (_show_experimental_audio_processors, config->show_experimental_audio_processors ());
1834 checked_set (_only_servers_encode, config->only_servers_encode ());
1835 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1836 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1837 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1838 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1839 checked_set (_log_debug_threed, config->log_types() & LogEntry::TYPE_DEBUG_THREE_D);
1840 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1841 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1842 checked_set (_log_debug_video_view, config->log_types() & LogEntry::TYPE_DEBUG_VIDEO_VIEW);
1843 checked_set (_log_debug_player, config->log_types() & LogEntry::TYPE_DEBUG_PLAYER);
1844 checked_set (_log_debug_audio_analysis, config->log_types() & LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS);
1845 checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
1846 #ifdef DCPOMATIC_WINDOWS
1847 checked_set (_win32_console, config->win32_console());
1851 void video_display_mode_changed ()
1853 if (_video_display_mode->GetSelection() == 0) {
1854 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_SIMPLE);
1856 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_OPENGL);
1860 void frames_in_memory_multiplier_changed ()
1862 Config::instance()->set_frames_in_memory_multiplier(_frames_in_memory_multiplier->GetValue());
1865 void show_experimental_audio_processors_changed ()
1867 Config::instance()->set_show_experimental_audio_processors(_show_experimental_audio_processors->GetValue());
1870 void only_servers_encode_changed ()
1872 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue());
1875 void dcp_metadata_filename_format_changed ()
1877 Config::instance()->set_dcp_metadata_filename_format(_dcp_metadata_filename_format->get());
1880 void dcp_asset_filename_format_changed ()
1882 Config::instance()->set_dcp_asset_filename_format(_dcp_asset_filename_format->get());
1888 if (_log_general->GetValue ()) {
1889 types |= LogEntry::TYPE_GENERAL;
1891 if (_log_warning->GetValue ()) {
1892 types |= LogEntry::TYPE_WARNING;
1894 if (_log_error->GetValue ()) {
1895 types |= LogEntry::TYPE_ERROR;
1897 if (_log_timing->GetValue ()) {
1898 types |= LogEntry::TYPE_TIMING;
1900 if (_log_debug_threed->GetValue ()) {
1901 types |= LogEntry::TYPE_DEBUG_THREE_D;
1903 if (_log_debug_encode->GetValue ()) {
1904 types |= LogEntry::TYPE_DEBUG_ENCODE;
1906 if (_log_debug_email->GetValue ()) {
1907 types |= LogEntry::TYPE_DEBUG_EMAIL;
1909 if (_log_debug_video_view->GetValue()) {
1910 types |= LogEntry::TYPE_DEBUG_VIDEO_VIEW;
1912 if (_log_debug_player->GetValue()) {
1913 types |= LogEntry::TYPE_DEBUG_PLAYER;
1915 if (_log_debug_audio_analysis->GetValue()) {
1916 types |= LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS;
1918 Config::instance()->set_log_types (types);
1921 #ifdef DCPOMATIC_WINDOWS
1922 void win32_console_changed ()
1924 Config::instance()->set_win32_console(_win32_console->GetValue());
1928 wxChoice* _video_display_mode = nullptr;
1929 wxSpinCtrl* _frames_in_memory_multiplier = nullptr;
1930 CheckBox* _show_experimental_audio_processors = nullptr;
1931 CheckBox* _only_servers_encode = nullptr;
1932 NameFormatEditor* _dcp_metadata_filename_format = nullptr;
1933 NameFormatEditor* _dcp_asset_filename_format = nullptr;
1934 CheckBox* _log_general = nullptr;
1935 CheckBox* _log_warning = nullptr;
1936 CheckBox* _log_error = nullptr;
1937 CheckBox* _log_timing = nullptr;
1938 CheckBox* _log_debug_threed = nullptr;
1939 CheckBox* _log_debug_encode = nullptr;
1940 CheckBox* _log_debug_email = nullptr;
1941 CheckBox* _log_debug_video_view = nullptr;
1942 CheckBox* _log_debug_player = nullptr;
1943 CheckBox* _log_debug_audio_analysis = nullptr;
1944 #ifdef DCPOMATIC_WINDOWS
1945 CheckBox* _win32_console = nullptr;
1950 wxPreferencesEditor*
1951 create_full_config_dialog ()
1953 auto e = new wxPreferencesEditor ();
1955 #ifdef DCPOMATIC_OSX
1956 /* Width that we force some of the config panels to be on OSX so that
1957 the containing window doesn't shrink too much when we select those panels.
1958 This is obviously an unpleasant hack.
1960 wxSize ps = wxSize(900, -1);
1961 int const border = 16;
1963 wxSize ps = wxSize (-1, -1);
1964 int const border = 8;
1967 e->AddPage (new FullGeneralPage (ps, border));
1968 e->AddPage (new SoundPage (ps, border));
1969 e->AddPage (new DefaultsPage (ps, border));
1970 e->AddPage (new EncodingServersPage(ps, border));
1971 #ifdef DCPOMATIC_GROK
1972 e->AddPage (new GPUPage (ps, border));
1974 e->AddPage (new KeysPage (ps, border));
1975 e->AddPage (new TMSPage (ps, border));
1976 e->AddPage (new EmailPage (ps, border));
1977 e->AddPage (new KDMEmailPage (ps, border));
1978 e->AddPage (new NotificationsPage (ps, border));
1979 e->AddPage (new CoverSheetPage (ps, border));
1980 e->AddPage (new IdentifiersPage (ps, border));
1981 e->AddPage (new NonStandardPage (ps, border));
1982 e->AddPage (new AdvancedPage (ps, border));