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"
48 #include "gpu_config_panel.h"
50 #include "lib/config.h"
51 #include "lib/cross.h"
52 #include "lib/dcp_content_type.h"
53 #include "lib/emailer.h"
54 #include "lib/exceptions.h"
55 #include "lib/filter.h"
57 #include "lib/ratio.h"
59 #include <dcp/certificate_chain.h>
60 #include <dcp/exceptions.h>
61 #include <dcp/filesystem.h>
62 #include <dcp/locale_convert.h>
63 #include <dcp/warnings.h>
64 LIBDCP_DISABLE_WARNINGS
65 #include <wx/filepicker.h>
66 #include <wx/preferences.h>
67 #include <wx/spinctrl.h>
68 #include <wx/stdpaths.h>
69 LIBDCP_ENABLE_WARNINGS
71 #include <boost/filesystem.hpp>
81 using std::shared_ptr;
85 using boost::optional;
86 #if BOOST_VERSION >= 106100
87 using namespace boost::placeholders;
89 using dcp::locale_convert;
92 class FullGeneralPage : public GeneralPage
95 FullGeneralPage (wxSize panel_size, int border)
96 : GeneralPage (panel_size, border)
100 void setup () override
102 auto table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
103 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
106 add_language_controls (table, r);
108 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic should use"), true, wxGBPosition (r, 0));
109 _master_encoding_threads = new wxSpinCtrl (_panel);
110 table->Add (_master_encoding_threads, wxGBPosition (r, 1));
113 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic encode server should use"), true, wxGBPosition (r, 0));
114 _server_encoding_threads = new wxSpinCtrl (_panel);
115 table->Add (_server_encoding_threads, wxGBPosition (r, 1));
118 add_label_to_sizer (table, _panel, _("Configuration file"), true, wxGBPosition (r, 0));
119 _config_file = new FilePickerCtrl(_panel, _("Select configuration file"), "*.xml", true, false, "ConfigFilePath");
120 table->Add (_config_file, wxGBPosition (r, 1));
123 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
124 _cinemas_file = new FilePickerCtrl(_panel, _("Select cinema and screen database file"), "*.xml", true, false, "CinemaDatabasePath");
125 table->Add (_cinemas_file, wxGBPosition (r, 1));
126 auto export_cinemas = new Button (_panel, _("Export..."));
127 table->Add (export_cinemas, wxGBPosition (r, 2));
130 add_label_to_sizer(table, _panel, _("Default \"add file\" location"), true, wxGBPosition(r, 0));
131 _default_add_file_location = new Choice(_panel);
132 table->Add(_default_add_file_location, wxGBPosition(r, 1));
135 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
136 _analyse_ebur128 = new CheckBox (_panel, _("Find integrated loudness, true peak and loudness range when analysing audio"));
137 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
141 _automatic_audio_analysis = new CheckBox (_panel, _("Automatically analyse content audio"));
142 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
145 add_update_controls (table, r);
147 _default_add_file_location->add(_("Same place as last time"));
148 _default_add_file_location->add(_("Same place as project"));
149 _default_add_file_location->bind(&FullGeneralPage::default_add_file_location_changed, this);
151 _config_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::config_file_changed, this));
152 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::cinemas_file_changed, this));
154 _master_encoding_threads->SetRange (1, 128);
155 _master_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::master_encoding_threads_changed, this));
156 _server_encoding_threads->SetRange (1, 128);
157 _server_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::server_encoding_threads_changed, this));
158 export_cinemas->Bind (wxEVT_BUTTON, boost::bind (&FullGeneralPage::export_cinemas_file, this));
160 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
161 _analyse_ebur128->bind(&FullGeneralPage::analyse_ebur128_changed, this);
163 _automatic_audio_analysis->bind(&FullGeneralPage::automatic_audio_analysis_changed, this);
166 void config_changed () override
168 auto config = Config::instance ();
170 checked_set (_master_encoding_threads, config->master_encoding_threads ());
171 checked_set (_server_encoding_threads, config->server_encoding_threads ());
172 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
173 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
175 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
176 checked_set (_config_file, config->config_read_file());
177 checked_set (_cinemas_file, config->cinemas_file());
178 checked_set(_default_add_file_location, config->default_add_file_location() == Config::DefaultAddFileLocation::SAME_AS_LAST_TIME ? 0 : 1);
180 GeneralPage::config_changed ();
183 void export_cinemas_file ()
186 _panel, _("Select Cinemas File"), wxEmptyString, wxEmptyString, wxT("XML files (*.xml)|*.xml"),
187 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
190 if (dialog.ShowModal() == wxID_OK) {
191 dcp::filesystem::copy_file(Config::instance()->cinemas_file(), wx_to_std(dialog.GetPath()), boost::filesystem::copy_option::overwrite_if_exists);
195 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
196 void analyse_ebur128_changed ()
198 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue());
202 void automatic_audio_analysis_changed ()
204 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue());
207 void master_encoding_threads_changed ()
209 Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue());
212 void server_encoding_threads_changed ()
214 Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue());
217 void config_file_changed ()
219 auto config = Config::instance();
220 auto const new_file = _config_file->path();
221 if (!new_file || *new_file == config->config_read_file()) {
224 bool copy_and_link = true;
225 if (dcp::filesystem::exists(*new_file)) {
226 ConfigMoveDialog dialog(_panel, *new_file);
227 if (dialog.ShowModal() == wxID_OK) {
228 copy_and_link = false;
234 if (new_file != config->config_read_file()) {
235 config->copy_and_link(*new_file);
238 config->link(*new_file);
242 void cinemas_file_changed ()
244 if (auto path = _cinemas_file->path()) {
245 Config::instance()->set_cinemas_file(*path);
249 void default_add_file_location_changed()
251 Config::instance()->set_default_add_file_location(
252 _default_add_file_location->get().get_value_or(0) == 0 ? Config::DefaultAddFileLocation::SAME_AS_LAST_TIME : Config::DefaultAddFileLocation::SAME_AS_PROJECT
256 Choice* _default_add_file_location;
257 wxSpinCtrl* _master_encoding_threads;
258 wxSpinCtrl* _server_encoding_threads;
259 FilePickerCtrl* _config_file;
260 FilePickerCtrl* _cinemas_file;
261 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
262 CheckBox* _analyse_ebur128;
264 CheckBox* _automatic_audio_analysis;
268 class DefaultsPage : public Page
271 DefaultsPage (wxSize panel_size, int border)
272 : Page (panel_size, border)
275 wxString GetName () const override
277 return _("Defaults");
281 wxBitmap GetLargeIcon () const override
283 return wxBitmap(icon_path("defaults"), wxBITMAP_TYPE_PNG);
288 void setup () override
290 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
291 table->AddGrowableCol (1, 1);
292 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
295 add_label_to_sizer (table, _panel, _("Default duration of still images"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
296 auto s = new wxBoxSizer (wxHORIZONTAL);
297 _still_length = new wxSpinCtrl (_panel);
298 s->Add (_still_length);
299 add_label_to_sizer (s, _panel, _("s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
303 add_label_to_sizer (table, _panel, _("Default directory for new films"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
304 #ifdef DCPOMATIC_USE_OWN_PICKER
305 _directory = new DirPickerCtrl (_panel);
307 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
309 table->Add (_directory, 1, wxEXPAND);
311 add_label_to_sizer (table, _panel, _("Default content type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
312 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
313 table->Add (_dcp_content_type);
315 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
316 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
317 table->Add (_dcp_audio_channels);
320 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
321 auto s = new wxBoxSizer (wxHORIZONTAL);
322 _j2k_bandwidth = new wxSpinCtrl (_panel);
323 s->Add (_j2k_bandwidth);
324 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
329 add_label_to_sizer (table, _panel, _("Default audio delay"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
330 auto s = new wxBoxSizer (wxHORIZONTAL);
331 _audio_delay = new wxSpinCtrl (_panel);
332 s->Add (_audio_delay);
333 add_label_to_sizer (s, _panel, _("ms"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
337 add_label_to_sizer (table, _panel, _("Default standard"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
338 _standard = new wxChoice (_panel, wxID_ANY);
339 table->Add (_standard);
341 _enable_audio_language = new CheckBox(_panel, _("Default audio language"));
342 table->Add(_enable_audio_language, 1, wxEXPAND | wxALIGN_CENTRE_VERTICAL);
343 _audio_language = new LanguageTagWidget(_panel, _("Default audio language to use for new DCPs"), Config::instance()->default_audio_language(), wxString("cmnr-Hant-"));
344 table->Add(_audio_language->sizer());
346 _enable_territory = new CheckBox(_panel, _("Default territory"));
347 table->Add(_enable_territory, 1, wxEXPAND | wxALIGN_CENTRE_VERTICAL);
348 _territory = new RegionSubtagWidget(_panel, _("Default territory to use for new DCPs"), Config::instance()->default_territory(), wxString("cmnr-Hant-"));
349 table->Add(_territory->sizer());
351 table->Add (_enable_metadata["facility"] = new CheckBox (_panel, _("Default facility")), 0, wxALIGN_CENTRE_VERTICAL);
352 table->Add (_metadata["facility"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
354 table->Add (_enable_metadata["studio"] = new CheckBox (_panel, _("Default studio")), 0, wxALIGN_CENTRE_VERTICAL);
355 table->Add (_metadata["studio"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
357 table->Add (_enable_metadata["chain"] = new CheckBox (_panel, _("Default chain")), 0, wxALIGN_CENTRE_VERTICAL);
358 table->Add (_metadata["chain"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
360 table->Add (_enable_metadata["distributor"] = new CheckBox (_panel, _("Default distributor")), 0, wxALIGN_CENTRE_VERTICAL);
361 table->Add (_metadata["distributor"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
363 add_label_to_sizer (table, _panel, _("Default KDM directory"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
364 #ifdef DCPOMATIC_USE_OWN_PICKER
365 _kdm_directory = new DirPickerCtrl (_panel);
367 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
369 table->Add (_kdm_directory, 1, wxEXPAND);
371 add_label_to_sizer (table, _panel, _("Default KDM type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
372 _kdm_type = new KDMChoice (_panel);
373 table->Add (_kdm_type, 1, wxEXPAND);
375 add_label_to_sizer (table, _panel, _("Default KDM duration"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
376 _kdm_duration = new wxSpinCtrl (_panel);
377 _kdm_duration_unit = new wxChoice (_panel, wxID_ANY);
378 auto kdm_duration_sizer = new wxBoxSizer (wxHORIZONTAL);
379 kdm_duration_sizer->Add (_kdm_duration, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
380 kdm_duration_sizer->Add (_kdm_duration_unit, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
381 table->Add (kdm_duration_sizer, 1, wxEXPAND);
383 table->Add (_use_isdcf_name_by_default = new CheckBox(_panel, _("Use ISDCF name by default")), 0, wxALIGN_CENTRE_VERTICAL);
385 _still_length->SetRange (1, 3600);
386 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
388 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
389 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
390 _kdm_type->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_type_changed, this));
391 _kdm_duration_unit->Append (_("days"));
392 _kdm_duration_unit->Append (_("weeks"));
393 _kdm_duration_unit->Append (_("months"));
394 _kdm_duration_unit->Append (_("years"));
396 _kdm_duration->Bind (wxEVT_SPINCTRL, boost::bind(&DefaultsPage::kdm_duration_changed, this));
397 _kdm_duration_unit->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_duration_changed, this));
399 _use_isdcf_name_by_default->bind(&DefaultsPage::use_isdcf_name_by_default_changed, this);
401 for (auto i: DCPContentType::all()) {
402 _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
405 setup_audio_channels_choice (_dcp_audio_channels, 2);
407 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
408 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
410 _j2k_bandwidth->SetRange (50, 250);
411 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
413 _audio_delay->SetRange (-1000, 1000);
414 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
416 _standard->Append (_("SMPTE"));
417 _standard->Append (_("Interop"));
418 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
420 for (auto const& i: _enable_metadata) {
421 i.second->bind(&DefaultsPage::metadata_changed, this);
424 for (auto const& i: _metadata) {
425 i.second->Bind (wxEVT_TEXT, boost::bind(&DefaultsPage::metadata_changed, this));
428 _enable_audio_language->bind(&DefaultsPage::enable_audio_language_toggled, this);
429 _audio_language->Changed.connect(boost::bind(&DefaultsPage::audio_language_changed, this));
431 _enable_territory->bind(&DefaultsPage::enable_territory_toggled, this);
432 _territory->Changed.connect(boost::bind(&DefaultsPage::territory_changed, this));
435 void config_changed () override
437 auto config = Config::instance ();
439 auto const ct = DCPContentType::all ();
440 for (size_t i = 0; i < ct.size(); ++i) {
441 if (ct[i] == config->default_dcp_content_type()) {
442 _dcp_content_type->SetSelection (i);
446 checked_set (_still_length, config->default_still_length ());
447 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
448 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
449 _kdm_type->set (config->default_kdm_type());
450 checked_set (_use_isdcf_name_by_default, config->use_isdcf_name_by_default());
451 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
452 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
453 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
454 checked_set (_audio_delay, config->default_audio_delay ());
455 checked_set (_standard, config->default_interop() ? 1 : 0);
456 auto dal = config->default_audio_language();
457 checked_set(_enable_audio_language, static_cast<bool>(dal));
458 checked_set(_audio_language, dal ? dal : boost::none);
459 auto dt = config->default_territory();
460 checked_set(_enable_territory, static_cast<bool>(dt));
461 checked_set(_territory, dt ? dt : boost::none);
463 auto metadata = config->default_metadata();
465 for (auto const& i: metadata) {
466 _enable_metadata[i.first]->SetValue(true);
467 checked_set (_metadata[i.first], i.second);
470 for (auto const& i: _enable_metadata) {
471 if (metadata.find(i.first) == metadata.end()) {
472 checked_set (i.second, false);
476 for (auto const& i: _metadata) {
477 if (metadata.find(i.first) == metadata.end()) {
478 checked_set (i.second, wxT(""));
482 checked_set (_kdm_duration, config->default_kdm_duration().duration);
483 switch (config->default_kdm_duration().unit) {
484 case RoughDuration::Unit::DAYS:
485 _kdm_duration->SetRange(1, 365);
486 checked_set (_kdm_duration_unit, 0);
488 case RoughDuration::Unit::WEEKS:
489 _kdm_duration->SetRange(1, 52);
490 checked_set (_kdm_duration_unit, 1);
492 case RoughDuration::Unit::MONTHS:
493 _kdm_duration->SetRange(1, 12);
494 checked_set (_kdm_duration_unit, 2);
496 case RoughDuration::Unit::YEARS:
497 _kdm_duration->SetRange(1, 40);
498 checked_set (_kdm_duration_unit, 3);
502 setup_sensitivity ();
505 void kdm_duration_changed ()
507 auto config = Config::instance();
508 auto duration = _kdm_duration->GetValue();
509 RoughDuration::Unit unit = RoughDuration::Unit::DAYS;
510 switch (_kdm_duration_unit->GetSelection()) {
512 unit = RoughDuration::Unit::DAYS;
515 unit = RoughDuration::Unit::WEEKS;
518 unit = RoughDuration::Unit::MONTHS;
521 unit = RoughDuration::Unit::YEARS;
524 config->set_default_kdm_duration (RoughDuration(duration, unit));
527 void j2k_bandwidth_changed ()
529 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
532 void audio_delay_changed ()
534 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
537 void dcp_audio_channels_changed ()
539 int const s = _dcp_audio_channels->GetSelection ();
540 if (s != wxNOT_FOUND) {
541 Config::instance()->set_default_dcp_audio_channels (
542 locale_convert<int>(string_client_data(_dcp_audio_channels->GetClientObject(s)))
547 void directory_changed ()
549 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
552 void kdm_directory_changed ()
554 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
557 void kdm_type_changed ()
559 Config::instance()->set_default_kdm_type(_kdm_type->get());
562 void use_isdcf_name_by_default_changed ()
564 Config::instance()->set_use_isdcf_name_by_default (_use_isdcf_name_by_default->GetValue());
567 void still_length_changed ()
569 Config::instance()->set_default_still_length (_still_length->GetValue ());
572 void dcp_content_type_changed ()
574 auto ct = DCPContentType::all ();
575 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
578 void standard_changed ()
580 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
583 void metadata_changed ()
585 map<string, string> metadata;
586 for (auto const& i: _enable_metadata) {
587 if (i.second->GetValue()) {
588 metadata[i.first] = wx_to_std(_metadata[i.first]->GetValue());
591 Config::instance()->set_default_metadata (metadata);
592 setup_sensitivity ();
595 void enable_audio_language_toggled()
598 audio_language_changed();
601 void audio_language_changed()
603 if (_enable_audio_language->get()) {
604 Config::instance()->set_default_audio_language(_audio_language->get().get_value_or(dcp::LanguageTag("en-US")));
606 Config::instance()->unset_default_audio_language();
610 void enable_territory_toggled()
616 void territory_changed()
618 if (_enable_territory->get()) {
619 Config::instance()->set_default_territory(_territory->get().get_value_or(dcp::LanguageTag::RegionSubtag("US")));
621 Config::instance()->unset_default_territory();
625 void setup_sensitivity ()
627 _audio_language->enable(_enable_audio_language->get());
628 _territory->enable(_enable_territory->get());
629 for (auto const& i: _enable_metadata) {
630 _metadata[i.first]->Enable(i.second->GetValue());
634 wxSpinCtrl* _j2k_bandwidth;
635 wxSpinCtrl* _audio_delay;
636 wxSpinCtrl* _still_length;
637 #ifdef DCPOMATIC_USE_OWN_PICKER
638 DirPickerCtrl* _directory;
639 DirPickerCtrl* _kdm_directory;
641 wxDirPickerCtrl* _directory;
642 wxDirPickerCtrl* _kdm_directory;
644 KDMChoice* _kdm_type;
645 wxSpinCtrl* _kdm_duration;
646 wxChoice* _kdm_duration_unit;
647 CheckBox* _use_isdcf_name_by_default;
648 wxChoice* _dcp_content_type;
649 wxChoice* _dcp_audio_channels;
651 CheckBox* _enable_audio_language;
652 LanguageTagWidget* _audio_language;
653 CheckBox* _enable_territory;
654 RegionSubtagWidget* _territory;
655 map<string, CheckBox*> _enable_metadata;
656 map<string, wxTextCtrl*> _metadata;
660 class EncodingServersPage : public Page
663 EncodingServersPage (wxSize panel_size, int border)
664 : Page (panel_size, border)
667 wxString GetName () const override
673 wxBitmap GetLargeIcon () const override
675 return wxBitmap(icon_path("servers"), wxBITMAP_TYPE_PNG);
680 void setup () override
682 _use_any_servers = new CheckBox (_panel, _("Search network for servers"));
683 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
685 vector<EditableListColumn> columns;
686 columns.push_back (EditableListColumn(_("IP address / host name")));
687 _servers_list = new EditableList<string, ServerDialog> (
690 boost::bind (&Config::servers, Config::instance()),
691 boost::bind (&Config::set_servers, Config::instance(), _1),
692 boost::bind (&EncodingServersPage::server_column, this, _1),
693 EditableListTitle::INVISIBLE,
694 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
697 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
699 _use_any_servers->bind(&EncodingServersPage::use_any_servers_changed, this);
702 void config_changed () override
704 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
705 _servers_list->refresh ();
708 void use_any_servers_changed ()
710 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
713 string server_column (string s)
718 CheckBox* _use_any_servers;
719 EditableList<string, ServerDialog>* _servers_list;
723 class TMSPage : public Page
726 TMSPage (wxSize panel_size, int border)
727 : Page (panel_size, border)
730 wxString GetName () const override
736 wxBitmap GetLargeIcon () const override
738 return wxBitmap(icon_path("tms"), wxBITMAP_TYPE_PNG);
743 void setup () override
745 _upload = new CheckBox (_panel, _("Upload DCP to TMS after creation"));
746 _panel->GetSizer()->Add (_upload, 0, wxALL | wxEXPAND, _border);
748 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
749 table->AddGrowableCol (1, 1);
750 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
752 add_label_to_sizer (table, _panel, _("Protocol"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
753 _tms_protocol = new wxChoice (_panel, wxID_ANY);
754 table->Add (_tms_protocol, 1, wxEXPAND);
756 _tms_passive = new CheckBox(_panel, _("Passive mode"));
757 table->Add(_tms_passive, 1, wxEXPAND);
760 add_label_to_sizer (table, _panel, _("IP address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
761 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
762 table->Add (_tms_ip, 1, wxEXPAND);
764 add_label_to_sizer (table, _panel, _("Target path"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
765 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
766 table->Add (_tms_path, 1, wxEXPAND);
768 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
769 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
770 table->Add (_tms_user, 1, wxEXPAND);
772 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
773 _tms_password = new PasswordEntry (_panel);
774 table->Add (_tms_password->get_panel(), 1, wxEXPAND);
776 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
777 _tms_protocol->Append (_("FTP (for Dolby)"));
779 _upload->bind(&TMSPage::upload_changed, this);
780 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
781 _tms_passive->bind(&TMSPage::tms_passive_changed, this);
783 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
784 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
785 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
786 _tms_password->Changed.connect (boost::bind (&TMSPage::tms_password_changed, this));
789 void config_changed () override
791 auto config = Config::instance ();
793 checked_set (_upload, config->upload_after_make_dcp());
794 checked_set (_tms_protocol, static_cast<int>(config->tms_protocol()));
795 checked_set(_tms_passive, config->tms_protocol() == FileTransferProtocol::FTP && config->tms_passive());
796 checked_set (_tms_ip, config->tms_ip ());
797 checked_set (_tms_path, config->tms_path ());
798 checked_set (_tms_user, config->tms_user ());
799 checked_set (_tms_password, config->tms_password ());
801 _tms_passive->Enable(config->tms_protocol() == FileTransferProtocol::FTP);
804 void upload_changed ()
806 Config::instance()->set_upload_after_make_dcp (_upload->GetValue());
809 void tms_protocol_changed ()
811 Config::instance()->set_tms_protocol(static_cast<FileTransferProtocol>(_tms_protocol->GetSelection()));
814 void tms_passive_changed()
816 Config::instance()->set_tms_passive(_tms_passive->get());
819 void tms_ip_changed ()
821 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
824 void tms_path_changed ()
826 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
829 void tms_user_changed ()
831 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
834 void tms_password_changed ()
836 Config::instance()->set_tms_password (_tms_password->get());
840 CheckBox* _tms_passive;
841 wxChoice* _tms_protocol;
843 wxTextCtrl* _tms_path;
844 wxTextCtrl* _tms_user;
845 PasswordEntry* _tms_password;
849 class EmailPage : public Page
852 EmailPage (wxSize panel_size, int border)
853 : Page (panel_size, border)
856 wxString GetName () const override
862 wxBitmap GetLargeIcon () const override
864 return wxBitmap(icon_path("email"), wxBITMAP_TYPE_PNG);
869 void setup () override
871 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
872 table->AddGrowableCol (1, 1);
873 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
875 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
877 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
878 _server = new wxTextCtrl (_panel, wxID_ANY);
879 s->Add (_server, 1, wxEXPAND | wxALL);
880 add_label_to_sizer (s, _panel, _("port"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
881 _port = new wxSpinCtrl (_panel, wxID_ANY);
882 _port->SetRange (0, 65535);
884 add_label_to_sizer (s, _panel, _("protocol"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
885 _protocol = new wxChoice (_panel, wxID_ANY);
886 /* Make sure this matches the switches in config_changed and port_changed below */
887 _protocol->Append (_("Auto"));
888 _protocol->Append (_("Plain"));
889 _protocol->Append (_("STARTTLS"));
890 _protocol->Append (_("SSL"));
891 s->Add (_protocol, 1, wxALIGN_CENTER_VERTICAL);
892 table->Add (s, 1, wxEXPAND | wxALL);
895 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
896 _user = new wxTextCtrl (_panel, wxID_ANY);
897 table->Add (_user, 1, wxEXPAND | wxALL);
899 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
900 _password = new PasswordEntry (_panel);
901 table->Add (_password->get_panel(), 1, wxEXPAND | wxALL);
903 table->AddSpacer (0);
904 _send_test_email = new Button (_panel, _("Send test email..."));
905 table->Add (_send_test_email);
907 _server->Bind (wxEVT_TEXT, boost::bind(&EmailPage::server_changed, this));
908 _port->Bind (wxEVT_SPINCTRL, boost::bind(&EmailPage::port_changed, this));
909 _protocol->Bind (wxEVT_CHOICE, boost::bind(&EmailPage::protocol_changed, this));
910 _user->Bind (wxEVT_TEXT, boost::bind(&EmailPage::user_changed, this));
911 _password->Changed.connect (boost::bind(&EmailPage::password_changed, this));
912 _send_test_email->Bind (wxEVT_BUTTON, boost::bind(&EmailPage::send_test_email_clicked, this));
915 void config_changed () override
917 auto config = Config::instance ();
919 checked_set (_server, config->mail_server());
920 checked_set (_port, config->mail_port());
921 switch (config->mail_protocol()) {
922 case EmailProtocol::AUTO:
923 checked_set (_protocol, 0);
925 case EmailProtocol::PLAIN:
926 checked_set (_protocol, 1);
928 case EmailProtocol::STARTTLS:
929 checked_set (_protocol, 2);
931 case EmailProtocol::SSL:
932 checked_set (_protocol, 3);
935 checked_set (_user, config->mail_user());
936 checked_set (_password, config->mail_password());
939 void server_changed ()
941 Config::instance()->set_mail_server(wx_to_std(_server->GetValue()));
946 Config::instance()->set_mail_port(_port->GetValue());
949 void protocol_changed ()
951 switch (_protocol->GetSelection()) {
953 Config::instance()->set_mail_protocol(EmailProtocol::AUTO);
956 Config::instance()->set_mail_protocol(EmailProtocol::PLAIN);
959 Config::instance()->set_mail_protocol(EmailProtocol::STARTTLS);
962 Config::instance()->set_mail_protocol(EmailProtocol::SSL);
969 Config::instance()->set_mail_user (wx_to_std (_user->GetValue ()));
972 void password_changed ()
974 Config::instance()->set_mail_password(_password->get());
977 void send_test_email_clicked ()
979 SendTestEmailDialog dialog(_panel);
980 if (dialog.ShowModal() != wxID_OK) {
985 wx_to_std(dialog.from()),
986 { wx_to_std(dialog.to()) },
987 wx_to_std(_("DCP-o-matic test email")),
988 wx_to_std(_("This is a test email from DCP-o-matic."))
990 auto config = Config::instance();
992 emailer.send(config->mail_server(), config->mail_port(), config->mail_protocol(), config->mail_user(), config->mail_password());
993 } catch (NetworkError& e) {
994 error_dialog(_panel, std_to_wx(e.summary()), std_to_wx(e.detail().get_value_or("")));
996 } catch (std::exception& e) {
997 error_dialog(_panel, _("Test email sending failed."), std_to_wx(e.what()));
1000 error_dialog(_panel, _("Test email sending failed."));
1003 message_dialog(_panel, _("Test email sent."));
1006 wxTextCtrl* _server;
1008 wxChoice* _protocol;
1010 PasswordEntry* _password;
1011 Button* _send_test_email;
1015 class KDMEmailPage : public Page
1019 KDMEmailPage (wxSize panel_size, int border)
1020 #ifdef DCPOMATIC_OSX
1021 /* We have to force both width and height of this one */
1022 : Page (wxSize (panel_size.GetWidth(), 128), border)
1024 : Page (panel_size, border)
1028 wxString GetName () const override
1030 return _("KDM Email");
1033 #ifdef DCPOMATIC_OSX
1034 wxBitmap GetLargeIcon () const override
1036 return wxBitmap(icon_path("kdm_email"), wxBITMAP_TYPE_PNG);
1041 void setup () override
1043 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1044 table->AddGrowableCol (1, 1);
1045 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1047 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1048 _subject = new wxTextCtrl (_panel, wxID_ANY);
1049 table->Add (_subject, 1, wxEXPAND | wxALL);
1051 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1052 _from = new wxTextCtrl (_panel, wxID_ANY);
1053 table->Add (_from, 1, wxEXPAND | wxALL);
1055 vector<EditableListColumn> columns;
1056 columns.push_back (EditableListColumn(_("Address")));
1057 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1058 _cc = new EditableList<string, EmailDialog> (
1061 bind (&Config::kdm_cc, Config::instance()),
1062 bind (&Config::set_kdm_cc, Config::instance(), _1),
1063 [] (string s, int) {
1066 EditableListTitle::VISIBLE,
1067 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
1069 table->Add (_cc, 1, wxEXPAND | wxALL);
1071 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1072 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1073 table->Add (_bcc, 1, wxEXPAND | wxALL);
1075 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1076 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1078 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1079 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1083 _subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1084 _from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1085 _bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1086 _email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1087 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_email, this));
1090 void config_changed () override
1092 auto config = Config::instance ();
1094 checked_set (_subject, config->kdm_subject ());
1095 checked_set (_from, config->kdm_from ());
1096 checked_set (_bcc, config->kdm_bcc ());
1097 checked_set (_email, Config::instance()->kdm_email ());
1100 void kdm_subject_changed ()
1102 Config::instance()->set_kdm_subject (wx_to_std (_subject->GetValue ()));
1105 void kdm_from_changed ()
1107 Config::instance()->set_kdm_from (wx_to_std (_from->GetValue ()));
1110 void kdm_bcc_changed ()
1112 Config::instance()->set_kdm_bcc (wx_to_std (_bcc->GetValue ()));
1115 void kdm_email_changed ()
1117 if (_email->GetValue().IsEmpty ()) {
1118 /* Sometimes we get sent an erroneous notification that the email
1119 is empty; I don't know why.
1123 Config::instance()->set_kdm_email (wx_to_std (_email->GetValue ()));
1128 Config::instance()->reset_kdm_email ();
1129 checked_set (_email, Config::instance()->kdm_email ());
1132 wxTextCtrl* _subject;
1134 EditableList<string, EmailDialog>* _cc;
1137 wxButton* _reset_email;
1141 class NotificationsPage : public Page
1144 NotificationsPage (wxSize panel_size, int border)
1145 #ifdef DCPOMATIC_OSX
1146 /* We have to force both width and height of this one */
1147 : Page (wxSize (panel_size.GetWidth(), 128), border)
1149 : Page (panel_size, border)
1153 wxString GetName () const override
1155 return _("Notifications");
1158 #ifdef DCPOMATIC_OSX
1159 wxBitmap GetLargeIcon () const override
1161 return wxBitmap(icon_path("notifications"), wxBITMAP_TYPE_PNG);
1166 void setup () override
1168 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1169 table->AddGrowableCol (1, 1);
1170 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1172 _enable_message_box = new CheckBox (_panel, _("Message box"));
1173 table->Add (_enable_message_box, 1, wxEXPAND | wxALL);
1174 table->AddSpacer (0);
1176 _enable_email = new CheckBox (_panel, _("Email"));
1177 table->Add (_enable_email, 1, wxEXPAND | wxALL);
1178 table->AddSpacer (0);
1180 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1181 _subject = new wxTextCtrl (_panel, wxID_ANY);
1182 table->Add (_subject, 1, wxEXPAND | wxALL);
1184 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1185 _from = new wxTextCtrl (_panel, wxID_ANY);
1186 table->Add (_from, 1, wxEXPAND | wxALL);
1188 add_label_to_sizer (table, _panel, _("To address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1189 _to = new wxTextCtrl (_panel, wxID_ANY);
1190 table->Add (_to, 1, wxEXPAND | wxALL);
1192 vector<EditableListColumn> columns;
1193 columns.push_back (EditableListColumn(_("Address")));
1194 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1195 _cc = new EditableList<string, EmailDialog> (
1198 bind (&Config::notification_cc, Config::instance()),
1199 bind (&Config::set_notification_cc, Config::instance(), _1),
1200 [] (string s, int) {
1203 EditableListTitle::VISIBLE,
1204 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
1206 table->Add (_cc, 1, wxEXPAND | wxALL);
1208 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1209 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1210 table->Add (_bcc, 1, wxEXPAND | wxALL);
1212 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1213 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1215 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1216 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1220 _enable_message_box->bind(&NotificationsPage::type_changed, this, _enable_message_box, Config::MESSAGE_BOX);
1221 _enable_email->bind(&NotificationsPage::type_changed, this, _enable_email, Config::EMAIL);
1223 _subject->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_subject_changed, this));
1224 _from->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_from_changed, this));
1225 _to->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_to_changed, this));
1226 _bcc->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_bcc_changed, this));
1227 _email->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_email_changed, this));
1228 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&NotificationsPage::reset_email, this));
1230 setup_sensitivity ();
1233 void setup_sensitivity ()
1235 bool const s = _enable_email->GetValue();
1236 _subject->Enable(s);
1242 _reset_email->Enable(s);
1245 void config_changed () override
1247 auto config = Config::instance ();
1249 checked_set (_enable_message_box, config->notification(Config::MESSAGE_BOX));
1250 checked_set (_enable_email, config->notification(Config::EMAIL));
1251 checked_set (_subject, config->notification_subject ());
1252 checked_set (_from, config->notification_from ());
1253 checked_set (_to, config->notification_to ());
1254 checked_set (_bcc, config->notification_bcc ());
1255 checked_set (_email, Config::instance()->notification_email ());
1257 setup_sensitivity ();
1260 void notification_subject_changed ()
1262 Config::instance()->set_notification_subject(wx_to_std(_subject->GetValue()));
1265 void notification_from_changed ()
1267 Config::instance()->set_notification_from(wx_to_std(_from->GetValue()));
1270 void notification_to_changed ()
1272 Config::instance()->set_notification_to(wx_to_std(_to->GetValue()));
1275 void notification_bcc_changed ()
1277 Config::instance()->set_notification_bcc(wx_to_std(_bcc->GetValue()));
1280 void notification_email_changed ()
1282 if (_email->GetValue().IsEmpty()) {
1283 /* Sometimes we get sent an erroneous notification that the email
1284 is empty; I don't know why.
1288 Config::instance()->set_notification_email(wx_to_std(_email->GetValue()));
1293 Config::instance()->reset_notification_email();
1294 checked_set (_email, Config::instance()->notification_email());
1297 void type_changed (CheckBox* b, Config::Notification n)
1299 Config::instance()->set_notification(n, b->GetValue());
1300 setup_sensitivity ();
1303 CheckBox* _enable_message_box;
1304 CheckBox* _enable_email;
1306 wxTextCtrl* _subject;
1309 EditableList<string, EmailDialog>* _cc;
1312 wxButton* _reset_email;
1316 class CoverSheetPage : public Page
1320 CoverSheetPage (wxSize panel_size, int border)
1321 #ifdef DCPOMATIC_OSX
1322 /* We have to force both width and height of this one */
1323 : Page (wxSize (panel_size.GetWidth(), 128), border)
1325 : Page (panel_size, border)
1329 wxString GetName () const override
1331 return _("Cover Sheet");
1334 #ifdef DCPOMATIC_OSX
1335 wxBitmap GetLargeIcon () const override
1337 return wxBitmap(icon_path("cover_sheet"), wxBITMAP_TYPE_PNG);
1342 void setup () override
1344 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1345 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
1347 _reset_cover_sheet = new Button (_panel, _("Reset to default text"));
1348 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
1350 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
1351 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
1354 void config_changed () override
1356 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1359 void cover_sheet_changed ()
1361 if (_cover_sheet->GetValue().IsEmpty ()) {
1362 /* Sometimes we get sent an erroneous notification that the cover sheet
1363 is empty; I don't know why.
1367 Config::instance()->set_cover_sheet(wx_to_std(_cover_sheet->GetValue()));
1370 void reset_cover_sheet ()
1372 Config::instance()->reset_cover_sheet();
1373 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1376 wxTextCtrl* _cover_sheet;
1377 wxButton* _reset_cover_sheet;
1381 class IdentifiersPage : public Page
1384 IdentifiersPage (wxSize panel_size, int border)
1385 : Page (panel_size, border)
1388 wxString GetName () const override
1390 return _("Identifiers");
1393 #ifdef DCPOMATIC_OSX
1394 wxBitmap GetLargeIcon () const override
1396 return wxBitmap(icon_path("identifiers"), wxBITMAP_TYPE_PNG);
1401 void setup () override
1403 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1404 table->AddGrowableCol (1, 1);
1406 add_label_to_sizer (table, _panel, _("Issuer"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1407 _issuer = new wxTextCtrl (_panel, wxID_ANY);
1408 _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."));
1409 table->Add (_issuer, 1, wxALL | wxEXPAND);
1411 add_label_to_sizer (table, _panel, _("Creator"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1412 _creator = new wxTextCtrl (_panel, wxID_ANY);
1413 _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."));
1414 table->Add (_creator, 1, wxALL | wxEXPAND);
1416 add_label_to_sizer (table, _panel, _("Company name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1417 _company_name = new wxTextCtrl (_panel, wxID_ANY);
1418 _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."));
1419 table->Add (_company_name, 1, wxALL | wxEXPAND);
1421 add_label_to_sizer (table, _panel, _("Product name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1422 _product_name = new wxTextCtrl (_panel, wxID_ANY);
1423 _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."));
1424 table->Add (_product_name, 1, wxALL | wxEXPAND);
1426 add_label_to_sizer (table, _panel, _("Product version"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1427 _product_version = new wxTextCtrl (_panel, wxID_ANY);
1428 _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."));
1429 table->Add (_product_version, 1, wxALL | wxEXPAND);
1431 add_label_to_sizer (table, _panel, _("JPEG2000 comment"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1432 _j2k_comment = new wxTextCtrl (_panel, wxID_ANY);
1433 _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."));
1434 table->Add (_j2k_comment, 1, wxALL | wxEXPAND);
1436 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1438 _issuer->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::issuer_changed, this));
1439 _creator->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::creator_changed, this));
1440 _company_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::company_name_changed, this));
1441 _product_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_name_changed, this));
1442 _product_version->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_version_changed, this));
1443 _j2k_comment->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::j2k_comment_changed, this));
1446 void config_changed () override
1448 auto config = Config::instance ();
1449 checked_set (_issuer, config->dcp_issuer ());
1450 checked_set (_creator, config->dcp_creator ());
1451 checked_set (_company_name, config->dcp_company_name ());
1452 checked_set (_product_name, config->dcp_product_name ());
1453 checked_set (_product_version, config->dcp_product_version ());
1454 checked_set (_j2k_comment, config->dcp_j2k_comment ());
1457 void issuer_changed ()
1459 Config::instance()->set_dcp_issuer(wx_to_std(_issuer->GetValue()));
1462 void creator_changed ()
1464 Config::instance()->set_dcp_creator(wx_to_std(_creator->GetValue()));
1467 void company_name_changed ()
1469 Config::instance()->set_dcp_company_name(wx_to_std(_company_name->GetValue()));
1472 void product_name_changed ()
1474 Config::instance()->set_dcp_product_name(wx_to_std(_product_name->GetValue()));
1477 void product_version_changed ()
1479 Config::instance()->set_dcp_product_version(wx_to_std(_product_version->GetValue()));
1482 void j2k_comment_changed ()
1484 Config::instance()->set_dcp_j2k_comment (wx_to_std(_j2k_comment->GetValue()));
1487 wxTextCtrl* _issuer;
1488 wxTextCtrl* _creator;
1489 wxTextCtrl* _company_name;
1490 wxTextCtrl* _product_name;
1491 wxTextCtrl* _product_version;
1492 wxTextCtrl* _j2k_comment;
1496 class NonStandardPage : public Page
1499 NonStandardPage(wxSize panel_size, int border)
1500 : Page(panel_size, border)
1503 wxString GetName() const override
1505 return _("Non-standard");
1508 #ifdef DCPOMATIC_OSX
1509 wxBitmap GetLargeIcon() const override
1511 return wxBitmap(icon_path("non_standard"), wxBITMAP_TYPE_PNG);
1516 void setup() override
1518 auto table = new wxFlexGridSizer(2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1519 table->AddGrowableCol(1, 1);
1520 _panel->GetSizer()->Add(table, 1, wxALL | wxEXPAND, _border);
1523 add_label_to_sizer(table, _panel, _("Maximum JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1524 auto s = new wxBoxSizer(wxHORIZONTAL);
1525 _maximum_j2k_bandwidth = new wxSpinCtrl(_panel);
1526 s->Add(_maximum_j2k_bandwidth, 1);
1527 add_label_to_sizer(s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxALIGN_CENTRE_VERTICAL);
1531 auto checkbox = [this, table](wxString name, CheckBox*& variable) {
1532 variable = new CheckBox(_panel, name);
1533 table->Add(variable, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1534 table->AddSpacer(0);
1537 checkbox(_("Allow any DCP frame rate"), _allow_any_dcp_frame_rate);
1539 _allow_any_container = new CheckBox(_panel, _("Allow full-frame and non-standard container ratios"));
1540 table->Add(_allow_any_container, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1541 auto restart = new StaticText(_panel, _("(restart DCP-o-matic to see all ratios)"));
1542 auto font = restart->GetFont();
1543 font.SetStyle(wxFONTSTYLE_ITALIC);
1544 font.SetPointSize(font.GetPointSize() - 1);
1545 restart->SetFont(font);
1546 table->Add(restart, 1, wxALIGN_CENTRE_VERTICAL | wxBOTTOM, DCPOMATIC_CHECKBOX_BOTTOM_PAD);
1547 restart->SetFont(font);
1549 checkbox(_("Allow creation of DCPs with 96kHz audio"), _allow_96khz_audio);
1550 checkbox(_("Allow mapping to all audio channels"), _use_all_audio_channels);
1551 checkbox(_("Allow use of SMPTE Bv2.0"), _allow_smpte_bv20);
1554 add_label_to_sizer(table, _panel, _("ISDCF name part length"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1555 auto s = new wxBoxSizer(wxHORIZONTAL);
1556 _isdcf_name_part_length = new wxSpinCtrl(_panel);
1557 s->Add(_isdcf_name_part_length, 1);
1561 _maximum_j2k_bandwidth->SetRange(1, 1000);
1562 _maximum_j2k_bandwidth->Bind(wxEVT_SPINCTRL, boost::bind(&NonStandardPage::maximum_j2k_bandwidth_changed, this));
1563 _allow_any_dcp_frame_rate->bind(&NonStandardPage::allow_any_dcp_frame_rate_changed, this);
1564 _allow_any_container->bind(&NonStandardPage::allow_any_container_changed, this);
1565 _allow_96khz_audio->bind(&NonStandardPage::allow_96khz_audio_changed, this);
1566 _use_all_audio_channels->bind(&NonStandardPage::use_all_channels_changed, this);
1567 _allow_smpte_bv20->bind(&NonStandardPage::allow_smpte_bv20_changed, this);
1568 _isdcf_name_part_length->SetRange(1, 256);
1569 _isdcf_name_part_length->Bind(wxEVT_SPINCTRL, boost::bind(&NonStandardPage::isdcf_name_part_length_changed, this));
1572 void config_changed() override
1574 auto config = Config::instance();
1576 checked_set(_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1577 checked_set(_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate());
1578 checked_set(_allow_any_container, config->allow_any_container());
1579 checked_set(_allow_96khz_audio, config->allow_96khz_audio());
1580 checked_set(_use_all_audio_channels, config->use_all_audio_channels());
1581 checked_set(_allow_smpte_bv20, config->allow_smpte_bv20());
1582 checked_set(_isdcf_name_part_length, config->isdcf_name_part_length());
1585 void maximum_j2k_bandwidth_changed()
1587 Config::instance()->set_maximum_j2k_bandwidth(_maximum_j2k_bandwidth->GetValue() * 1000000);
1590 void allow_any_dcp_frame_rate_changed()
1592 Config::instance()->set_allow_any_dcp_frame_rate(_allow_any_dcp_frame_rate->GetValue());
1595 void allow_any_container_changed()
1597 Config::instance()->set_allow_any_container(_allow_any_container->GetValue());
1600 void allow_96khz_audio_changed()
1602 Config::instance()->set_allow_96hhz_audio(_allow_96khz_audio->GetValue());
1605 void use_all_channels_changed()
1607 Config::instance()->set_use_all_audio_channels(_use_all_audio_channels->GetValue());
1610 void allow_smpte_bv20_changed()
1612 Config::instance()->set_allow_smpte_bv20(_allow_smpte_bv20->GetValue());
1615 void isdcf_name_part_length_changed()
1617 Config::instance()->set_isdcf_name_part_length(_isdcf_name_part_length->GetValue());
1620 wxSpinCtrl* _maximum_j2k_bandwidth = nullptr;
1621 CheckBox* _allow_any_dcp_frame_rate = nullptr;
1622 CheckBox* _allow_any_container = nullptr;
1623 CheckBox* _allow_96khz_audio = nullptr;
1624 CheckBox* _use_all_audio_channels = nullptr;
1625 CheckBox* _allow_smpte_bv20 = nullptr;
1626 wxSpinCtrl* _isdcf_name_part_length = nullptr;
1631 /** @class AdvancedPage
1632 * @brief Advanced page of the preferences dialog.
1634 class AdvancedPage : public Page
1637 AdvancedPage (wxSize panel_size, int border)
1638 : Page (panel_size, border)
1641 wxString GetName () const override
1643 return _("Advanced");
1646 #ifdef DCPOMATIC_OSX
1647 wxBitmap GetLargeIcon () const override
1649 return wxBitmap(icon_path("advanced"), wxBITMAP_TYPE_PNG);
1654 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1656 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1658 flags |= wxALIGN_RIGHT;
1661 wxStaticText* m = new StaticText (parent, text);
1662 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1665 void setup () override
1667 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1668 table->AddGrowableCol (1, 1);
1669 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1671 add_label_to_sizer (table, _panel, _("Video display mode"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1672 _video_display_mode = new wxChoice (_panel, wxID_ANY);
1673 table->Add (_video_display_mode);
1675 auto restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to change display mode)"), false);
1676 auto font = restart->GetFont();
1677 font.SetStyle (wxFONTSTYLE_ITALIC);
1678 font.SetPointSize (font.GetPointSize() - 1);
1679 restart->SetFont (font);
1680 table->AddSpacer (0);
1682 _show_experimental_audio_processors = new CheckBox (_panel, _("Show experimental audio processors"));
1683 table->Add (_show_experimental_audio_processors, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1684 table->AddSpacer (0);
1686 _only_servers_encode = new CheckBox (_panel, _("Only servers encode"));
1687 table->Add (_only_servers_encode, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1688 table->AddSpacer (0);
1691 add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1692 auto s = new wxBoxSizer (wxHORIZONTAL);
1693 _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
1694 s->Add (_frames_in_memory_multiplier, 1);
1699 auto format = create_label (_panel, _("DCP metadata filename format"), true);
1700 #ifdef DCPOMATIC_OSX
1701 auto align = new wxBoxSizer (wxHORIZONTAL);
1702 align->Add (format, 0, wxTOP, 2);
1703 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1705 table->Add (format, 0, wxTOP | wxLEFT | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1707 dcp::NameFormat::Map titles;
1708 titles['t'] = wx_to_std (_("type (cpl/pkl)"));
1709 dcp::NameFormat::Map examples;
1710 examples['t'] = "cpl";
1711 _dcp_metadata_filename_format = new NameFormatEditor (
1712 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1714 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1718 auto format = create_label (_panel, _("DCP asset filename format"), true);
1719 #ifdef DCPOMATIC_OSX
1720 auto align = new wxBoxSizer (wxHORIZONTAL);
1721 align->Add (format, 0, wxTOP, 2);
1722 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1724 table->Add (format, 0, wxTOP | wxLEFT | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1726 dcp::NameFormat::Map titles;
1727 titles['t'] = wx_to_std (_("type (j2c/pcm/sub)"));
1728 titles['r'] = wx_to_std (_("reel number"));
1729 titles['n'] = wx_to_std (_("number of reels"));
1730 titles['c'] = wx_to_std (_("content filename"));
1731 dcp::NameFormat::Map examples;
1732 examples['t'] = "j2c";
1733 examples['r'] = "1";
1734 examples['n'] = "4";
1735 examples['c'] = "myfile.mp4";
1736 _dcp_asset_filename_format = new NameFormatEditor (
1737 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1739 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1743 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1744 auto t = new wxFlexGridSizer (2);
1745 _log_general = new CheckBox (_panel, _("General"));
1746 t->Add (_log_general, 1, wxEXPAND | wxALL);
1747 _log_warning = new CheckBox (_panel, _("Warnings"));
1748 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1749 _log_error = new CheckBox (_panel, _("Errors"));
1750 t->Add (_log_error, 1, wxEXPAND | wxALL);
1751 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1752 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
1753 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1754 _log_debug_threed = new CheckBox (_panel, _("Debug: 3D"));
1755 t->Add (_log_debug_threed, 1, wxEXPAND | wxALL);
1756 _log_debug_encode = new CheckBox (_panel, _("Debug: encode"));
1757 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1758 _log_debug_email = new CheckBox (_panel, _("Debug: email sending"));
1759 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1760 _log_debug_video_view = new CheckBox (_panel, _("Debug: video view"));
1761 t->Add (_log_debug_video_view, 1, wxEXPAND | wxALL);
1762 _log_debug_player = new CheckBox (_panel, _("Debug: player"));
1763 t->Add (_log_debug_player, 1, wxEXPAND | wxALL);
1764 _log_debug_audio_analysis = new CheckBox (_panel, _("Debug: audio analysis"));
1765 t->Add (_log_debug_audio_analysis, 1, wxEXPAND | wxALL);
1766 table->Add (t, 0, wxALL, 6);
1769 #ifdef DCPOMATIC_WINDOWS
1770 _win32_console = new CheckBox (_panel, _("Open console window"));
1771 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1772 table->AddSpacer (0);
1775 _video_display_mode->Append (_("Simple (safer)"));
1776 #if wxCHECK_VERSION(3, 1, 0)
1777 _video_display_mode->Append (_("OpenGL (faster)"));
1779 _video_display_mode->Bind (wxEVT_CHOICE, boost::bind(&AdvancedPage::video_display_mode_changed, this));
1780 _show_experimental_audio_processors->bind(&AdvancedPage::show_experimental_audio_processors_changed, this);
1781 _only_servers_encode->bind(&AdvancedPage::only_servers_encode_changed, this);
1782 _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
1783 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1784 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1785 _log_general->bind(&AdvancedPage::log_changed, this);
1786 _log_warning->bind(&AdvancedPage::log_changed, this);
1787 _log_error->bind(&AdvancedPage::log_changed, this);
1788 _log_timing->bind(&AdvancedPage::log_changed, this);
1789 _log_debug_threed->bind(&AdvancedPage::log_changed, this);
1790 _log_debug_encode->bind(&AdvancedPage::log_changed, this);
1791 _log_debug_email->bind(&AdvancedPage::log_changed, this);
1792 _log_debug_video_view->bind(&AdvancedPage::log_changed, this);
1793 _log_debug_player->bind(&AdvancedPage::log_changed, this);
1794 _log_debug_audio_analysis->bind(&AdvancedPage::log_changed, this);
1795 #ifdef DCPOMATIC_WINDOWS
1796 _win32_console->bind(&AdvancedPage::win32_console_changed, this);
1800 void config_changed () override
1802 auto config = Config::instance ();
1804 switch (config->video_view_type()) {
1805 case Config::VIDEO_VIEW_SIMPLE:
1806 checked_set (_video_display_mode, 0);
1808 case Config::VIDEO_VIEW_OPENGL:
1809 checked_set (_video_display_mode, 1);
1812 checked_set (_show_experimental_audio_processors, config->show_experimental_audio_processors ());
1813 checked_set (_only_servers_encode, config->only_servers_encode ());
1814 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1815 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1816 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1817 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1818 checked_set (_log_debug_threed, config->log_types() & LogEntry::TYPE_DEBUG_THREE_D);
1819 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1820 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1821 checked_set (_log_debug_video_view, config->log_types() & LogEntry::TYPE_DEBUG_VIDEO_VIEW);
1822 checked_set (_log_debug_player, config->log_types() & LogEntry::TYPE_DEBUG_PLAYER);
1823 checked_set (_log_debug_audio_analysis, config->log_types() & LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS);
1824 checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
1825 #ifdef DCPOMATIC_WINDOWS
1826 checked_set (_win32_console, config->win32_console());
1830 void video_display_mode_changed ()
1832 if (_video_display_mode->GetSelection() == 0) {
1833 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_SIMPLE);
1835 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_OPENGL);
1839 void frames_in_memory_multiplier_changed ()
1841 Config::instance()->set_frames_in_memory_multiplier(_frames_in_memory_multiplier->GetValue());
1844 void show_experimental_audio_processors_changed ()
1846 Config::instance()->set_show_experimental_audio_processors(_show_experimental_audio_processors->GetValue());
1849 void only_servers_encode_changed ()
1851 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue());
1854 void dcp_metadata_filename_format_changed ()
1856 Config::instance()->set_dcp_metadata_filename_format(_dcp_metadata_filename_format->get());
1859 void dcp_asset_filename_format_changed ()
1861 Config::instance()->set_dcp_asset_filename_format(_dcp_asset_filename_format->get());
1867 if (_log_general->GetValue ()) {
1868 types |= LogEntry::TYPE_GENERAL;
1870 if (_log_warning->GetValue ()) {
1871 types |= LogEntry::TYPE_WARNING;
1873 if (_log_error->GetValue ()) {
1874 types |= LogEntry::TYPE_ERROR;
1876 if (_log_timing->GetValue ()) {
1877 types |= LogEntry::TYPE_TIMING;
1879 if (_log_debug_threed->GetValue ()) {
1880 types |= LogEntry::TYPE_DEBUG_THREE_D;
1882 if (_log_debug_encode->GetValue ()) {
1883 types |= LogEntry::TYPE_DEBUG_ENCODE;
1885 if (_log_debug_email->GetValue ()) {
1886 types |= LogEntry::TYPE_DEBUG_EMAIL;
1888 if (_log_debug_video_view->GetValue()) {
1889 types |= LogEntry::TYPE_DEBUG_VIDEO_VIEW;
1891 if (_log_debug_player->GetValue()) {
1892 types |= LogEntry::TYPE_DEBUG_PLAYER;
1894 if (_log_debug_audio_analysis->GetValue()) {
1895 types |= LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS;
1897 Config::instance()->set_log_types (types);
1900 #ifdef DCPOMATIC_WINDOWS
1901 void win32_console_changed ()
1903 Config::instance()->set_win32_console(_win32_console->GetValue());
1907 wxChoice* _video_display_mode = nullptr;
1908 wxSpinCtrl* _frames_in_memory_multiplier = nullptr;
1909 CheckBox* _show_experimental_audio_processors = nullptr;
1910 CheckBox* _only_servers_encode = nullptr;
1911 NameFormatEditor* _dcp_metadata_filename_format = nullptr;
1912 NameFormatEditor* _dcp_asset_filename_format = nullptr;
1913 CheckBox* _log_general = nullptr;
1914 CheckBox* _log_warning = nullptr;
1915 CheckBox* _log_error = nullptr;
1916 CheckBox* _log_timing = nullptr;
1917 CheckBox* _log_debug_threed = nullptr;
1918 CheckBox* _log_debug_encode = nullptr;
1919 CheckBox* _log_debug_email = nullptr;
1920 CheckBox* _log_debug_video_view = nullptr;
1921 CheckBox* _log_debug_player = nullptr;
1922 CheckBox* _log_debug_audio_analysis = nullptr;
1923 #ifdef DCPOMATIC_WINDOWS
1924 CheckBox* _win32_console = nullptr;
1929 wxPreferencesEditor*
1930 create_full_config_dialog ()
1932 auto e = new wxPreferencesEditor ();
1934 #ifdef DCPOMATIC_OSX
1935 /* Width that we force some of the config panels to be on OSX so that
1936 the containing window doesn't shrink too much when we select those panels.
1937 This is obviously an unpleasant hack.
1939 wxSize ps = wxSize (750, -1);
1940 int const border = 16;
1942 wxSize ps = wxSize (-1, -1);
1943 int const border = 8;
1946 e->AddPage (new FullGeneralPage (ps, border));
1947 e->AddPage (new SoundPage (ps, border));
1948 e->AddPage (new DefaultsPage (ps, border));
1949 e->AddPage (new EncodingServersPage(ps, border));
1950 e->AddPage (new GPUPage (ps, border));
1951 e->AddPage (new KeysPage (ps, border));
1952 e->AddPage (new TMSPage (ps, border));
1953 e->AddPage (new EmailPage (ps, border));
1954 e->AddPage (new KDMEmailPage (ps, border));
1955 e->AddPage (new NotificationsPage (ps, border));
1956 e->AddPage (new CoverSheetPage (ps, border));
1957 e->AddPage (new IdentifiersPage (ps, border));
1958 e->AddPage (new NonStandardPage (ps, border));
1959 e->AddPage (new AdvancedPage (ps, border));