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 "lib/config.h"
50 #include "lib/cross.h"
51 #include "lib/dcp_content_type.h"
52 #include "lib/email.h"
53 #include "lib/exceptions.h"
54 #include "lib/filter.h"
56 #include "lib/ratio.h"
58 #include <dcp/certificate_chain.h>
59 #include <dcp/exceptions.h>
60 #include <dcp/filesystem.h>
61 #include <dcp/locale_convert.h>
62 #include <dcp/warnings.h>
63 LIBDCP_DISABLE_WARNINGS
64 #include <wx/filepicker.h>
65 #include <wx/preferences.h>
66 #include <wx/spinctrl.h>
67 #include <wx/stdpaths.h>
68 LIBDCP_ENABLE_WARNINGS
70 #include <boost/filesystem.hpp>
80 using std::shared_ptr;
84 using boost::optional;
85 #if BOOST_VERSION >= 106100
86 using namespace boost::placeholders;
88 using dcp::locale_convert;
91 class FullGeneralPage : public GeneralPage
94 FullGeneralPage (wxSize panel_size, int border)
95 : GeneralPage (panel_size, border)
99 void setup () override
101 auto table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
102 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
105 add_language_controls (table, r);
107 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic should use"), true, wxGBPosition (r, 0));
108 _master_encoding_threads = new wxSpinCtrl (_panel);
109 table->Add (_master_encoding_threads, wxGBPosition (r, 1));
112 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic encode server should use"), true, wxGBPosition (r, 0));
113 _server_encoding_threads = new wxSpinCtrl (_panel);
114 table->Add (_server_encoding_threads, wxGBPosition (r, 1));
117 add_label_to_sizer (table, _panel, _("Configuration file"), true, wxGBPosition (r, 0));
118 _config_file = new FilePickerCtrl(_panel, _("Select configuration file"), "*.xml", true, false, "ConfigFilePath");
119 table->Add (_config_file, wxGBPosition (r, 1));
122 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
123 _cinemas_file = new FilePickerCtrl(_panel, _("Select cinema and screen database file"), "*.xml", true, false, "CinemaDatabasePath");
124 table->Add (_cinemas_file, wxGBPosition (r, 1));
125 auto export_cinemas = new Button (_panel, _("Export..."));
126 table->Add (export_cinemas, wxGBPosition (r, 2));
129 add_label_to_sizer(table, _panel, _("Default \"add file\" location"), true, wxGBPosition(r, 0));
130 _default_add_file_location = new Choice(_panel);
131 table->Add(_default_add_file_location, wxGBPosition(r, 1));
134 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
135 _analyse_ebur128 = new CheckBox (_panel, _("Find integrated loudness, true peak and loudness range when analysing audio"));
136 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
140 _automatic_audio_analysis = new CheckBox (_panel, _("Automatically analyse content audio"));
141 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
144 add_update_controls (table, r);
146 _default_add_file_location->add(_("Same place as last time"));
147 _default_add_file_location->add(_("Same place as project"));
148 _default_add_file_location->bind(&FullGeneralPage::default_add_file_location_changed, this);
150 _config_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::config_file_changed, this));
151 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::cinemas_file_changed, this));
153 _master_encoding_threads->SetRange (1, 128);
154 _master_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::master_encoding_threads_changed, this));
155 _server_encoding_threads->SetRange (1, 128);
156 _server_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::server_encoding_threads_changed, this));
157 export_cinemas->Bind (wxEVT_BUTTON, boost::bind (&FullGeneralPage::export_cinemas_file, this));
159 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
160 _analyse_ebur128->bind(&FullGeneralPage::analyse_ebur128_changed, this);
162 _automatic_audio_analysis->bind(&FullGeneralPage::automatic_audio_analysis_changed, this);
165 void config_changed () override
167 auto config = Config::instance ();
169 checked_set (_master_encoding_threads, config->master_encoding_threads ());
170 checked_set (_server_encoding_threads, config->server_encoding_threads ());
171 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
172 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
174 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
175 checked_set (_config_file, config->config_read_file());
176 checked_set (_cinemas_file, config->cinemas_file());
177 checked_set(_default_add_file_location, config->default_add_file_location() == Config::DefaultAddFileLocation::SAME_AS_LAST_TIME ? 0 : 1);
179 GeneralPage::config_changed ();
182 void export_cinemas_file ()
185 _panel, _("Select Cinemas File"), wxEmptyString, wxEmptyString, wxT("XML files (*.xml)|*.xml"),
186 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
189 if (dialog.ShowModal() == wxID_OK) {
190 dcp::filesystem::copy_file(Config::instance()->cinemas_file(), wx_to_std(dialog.GetPath()), boost::filesystem::copy_option::overwrite_if_exists);
194 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
195 void analyse_ebur128_changed ()
197 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue());
201 void automatic_audio_analysis_changed ()
203 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue());
206 void master_encoding_threads_changed ()
208 Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue());
211 void server_encoding_threads_changed ()
213 Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue());
216 void config_file_changed ()
218 auto config = Config::instance();
219 auto const new_file = _config_file->path();
220 if (!new_file || *new_file == config->config_read_file()) {
223 bool copy_and_link = true;
224 if (dcp::filesystem::exists(*new_file)) {
225 ConfigMoveDialog dialog(_panel, *new_file);
226 if (dialog.ShowModal() == wxID_OK) {
227 copy_and_link = false;
233 if (new_file != config->config_read_file()) {
234 config->copy_and_link(*new_file);
237 config->link(*new_file);
241 void cinemas_file_changed ()
243 if (auto path = _cinemas_file->path()) {
244 Config::instance()->set_cinemas_file(*path);
248 void default_add_file_location_changed()
250 Config::instance()->set_default_add_file_location(
251 _default_add_file_location->get().get_value_or(0) == 0 ? Config::DefaultAddFileLocation::SAME_AS_LAST_TIME : Config::DefaultAddFileLocation::SAME_AS_PROJECT
255 Choice* _default_add_file_location;
256 wxSpinCtrl* _master_encoding_threads;
257 wxSpinCtrl* _server_encoding_threads;
258 FilePickerCtrl* _config_file;
259 FilePickerCtrl* _cinemas_file;
260 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
261 CheckBox* _analyse_ebur128;
263 CheckBox* _automatic_audio_analysis;
267 class DefaultsPage : public Page
270 DefaultsPage (wxSize panel_size, int border)
271 : Page (panel_size, border)
274 wxString GetName () const override
276 return _("Defaults");
280 wxBitmap GetLargeIcon () const override
282 return wxBitmap(icon_path("defaults"), wxBITMAP_TYPE_PNG);
287 void setup () override
289 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
290 table->AddGrowableCol (1, 1);
291 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
294 add_label_to_sizer (table, _panel, _("Default duration of still images"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
295 auto s = new wxBoxSizer (wxHORIZONTAL);
296 _still_length = new wxSpinCtrl (_panel);
297 s->Add (_still_length);
298 add_label_to_sizer (s, _panel, _("s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
302 add_label_to_sizer (table, _panel, _("Default directory for new films"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
303 #ifdef DCPOMATIC_USE_OWN_PICKER
304 _directory = new DirPickerCtrl (_panel);
306 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
308 table->Add (_directory, 1, wxEXPAND);
310 add_label_to_sizer (table, _panel, _("Default content type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
311 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
312 table->Add (_dcp_content_type);
314 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
315 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
316 table->Add (_dcp_audio_channels);
319 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
320 auto s = new wxBoxSizer (wxHORIZONTAL);
321 _j2k_bandwidth = new wxSpinCtrl (_panel);
322 s->Add (_j2k_bandwidth);
323 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
328 add_label_to_sizer (table, _panel, _("Default audio delay"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
329 auto s = new wxBoxSizer (wxHORIZONTAL);
330 _audio_delay = new wxSpinCtrl (_panel);
331 s->Add (_audio_delay);
332 add_label_to_sizer (s, _panel, _("ms"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
336 add_label_to_sizer (table, _panel, _("Default standard"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
337 _standard = new wxChoice (_panel, wxID_ANY);
338 table->Add (_standard);
340 _enable_audio_language = new CheckBox(_panel, _("Default audio language"));
341 table->Add(_enable_audio_language, 1, wxEXPAND | wxALIGN_CENTRE_VERTICAL);
342 _audio_language = new LanguageTagWidget(_panel, _("Default audio language to use for new DCPs"), Config::instance()->default_audio_language(), wxString("cmnr-Hant-"));
343 table->Add(_audio_language->sizer());
345 _enable_territory = new CheckBox(_panel, _("Default territory"));
346 table->Add(_enable_territory, 1, wxEXPAND | wxALIGN_CENTRE_VERTICAL);
347 _territory = new RegionSubtagWidget(_panel, _("Default territory to use for new DCPs"), Config::instance()->default_territory(), wxString("cmnr-Hant-"));
348 table->Add(_territory->sizer());
350 table->Add (_enable_metadata["facility"] = new CheckBox (_panel, _("Default facility")), 0, wxALIGN_CENTRE_VERTICAL);
351 table->Add (_metadata["facility"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
353 table->Add (_enable_metadata["studio"] = new CheckBox (_panel, _("Default studio")), 0, wxALIGN_CENTRE_VERTICAL);
354 table->Add (_metadata["studio"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
356 table->Add (_enable_metadata["chain"] = new CheckBox (_panel, _("Default chain")), 0, wxALIGN_CENTRE_VERTICAL);
357 table->Add (_metadata["chain"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
359 table->Add (_enable_metadata["distributor"] = new CheckBox (_panel, _("Default distributor")), 0, wxALIGN_CENTRE_VERTICAL);
360 table->Add (_metadata["distributor"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
362 add_label_to_sizer (table, _panel, _("Default KDM directory"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
363 #ifdef DCPOMATIC_USE_OWN_PICKER
364 _kdm_directory = new DirPickerCtrl (_panel);
366 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
368 table->Add (_kdm_directory, 1, wxEXPAND);
370 add_label_to_sizer (table, _panel, _("Default KDM type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
371 _kdm_type = new KDMChoice (_panel);
372 table->Add (_kdm_type, 1, wxEXPAND);
374 add_label_to_sizer (table, _panel, _("Default KDM duration"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
375 _kdm_duration = new wxSpinCtrl (_panel);
376 _kdm_duration_unit = new wxChoice (_panel, wxID_ANY);
377 auto kdm_duration_sizer = new wxBoxSizer (wxHORIZONTAL);
378 kdm_duration_sizer->Add (_kdm_duration, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
379 kdm_duration_sizer->Add (_kdm_duration_unit, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
380 table->Add (kdm_duration_sizer, 1, wxEXPAND);
382 table->Add (_use_isdcf_name_by_default = new CheckBox(_panel, _("Use ISDCF name by default")), 0, wxALIGN_CENTRE_VERTICAL);
384 _still_length->SetRange (1, 3600);
385 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
387 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
388 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
389 _kdm_type->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_type_changed, this));
390 _kdm_duration_unit->Append (_("days"));
391 _kdm_duration_unit->Append (_("weeks"));
392 _kdm_duration_unit->Append (_("months"));
393 _kdm_duration_unit->Append (_("years"));
395 _kdm_duration->Bind (wxEVT_SPINCTRL, boost::bind(&DefaultsPage::kdm_duration_changed, this));
396 _kdm_duration_unit->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_duration_changed, this));
398 _use_isdcf_name_by_default->bind(&DefaultsPage::use_isdcf_name_by_default_changed, this);
400 for (auto i: DCPContentType::all()) {
401 _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
404 setup_audio_channels_choice (_dcp_audio_channels, 2);
406 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
407 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
409 _j2k_bandwidth->SetRange (50, 250);
410 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
412 _audio_delay->SetRange (-1000, 1000);
413 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
415 _standard->Append (_("SMPTE"));
416 _standard->Append (_("Interop"));
417 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
419 for (auto const& i: _enable_metadata) {
420 i.second->bind(&DefaultsPage::metadata_changed, this);
423 for (auto const& i: _metadata) {
424 i.second->Bind (wxEVT_TEXT, boost::bind(&DefaultsPage::metadata_changed, this));
427 _enable_audio_language->bind(&DefaultsPage::enable_audio_language_toggled, this);
428 _audio_language->Changed.connect(boost::bind(&DefaultsPage::audio_language_changed, this));
430 _enable_territory->bind(&DefaultsPage::enable_territory_toggled, this);
431 _territory->Changed.connect(boost::bind(&DefaultsPage::territory_changed, this));
434 void config_changed () override
436 auto config = Config::instance ();
438 auto const ct = DCPContentType::all ();
439 for (size_t i = 0; i < ct.size(); ++i) {
440 if (ct[i] == config->default_dcp_content_type()) {
441 _dcp_content_type->SetSelection (i);
445 checked_set (_still_length, config->default_still_length ());
446 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
447 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
448 _kdm_type->set (config->default_kdm_type());
449 checked_set (_use_isdcf_name_by_default, config->use_isdcf_name_by_default());
450 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
451 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
452 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
453 checked_set (_audio_delay, config->default_audio_delay ());
454 checked_set (_standard, config->default_interop() ? 1 : 0);
455 auto dal = config->default_audio_language();
456 checked_set(_enable_audio_language, static_cast<bool>(dal));
457 checked_set(_audio_language, dal ? dal : boost::none);
458 auto dt = config->default_territory();
459 checked_set(_enable_territory, static_cast<bool>(dt));
460 checked_set(_territory, dt ? dt : boost::none);
462 auto metadata = config->default_metadata();
464 for (auto const& i: metadata) {
465 _enable_metadata[i.first]->SetValue(true);
466 checked_set (_metadata[i.first], i.second);
469 for (auto const& i: _enable_metadata) {
470 if (metadata.find(i.first) == metadata.end()) {
471 checked_set (i.second, false);
475 for (auto const& i: _metadata) {
476 if (metadata.find(i.first) == metadata.end()) {
477 checked_set (i.second, wxT(""));
481 checked_set (_kdm_duration, config->default_kdm_duration().duration);
482 switch (config->default_kdm_duration().unit) {
483 case RoughDuration::Unit::DAYS:
484 _kdm_duration->SetRange(1, 365);
485 checked_set (_kdm_duration_unit, 0);
487 case RoughDuration::Unit::WEEKS:
488 _kdm_duration->SetRange(1, 52);
489 checked_set (_kdm_duration_unit, 1);
491 case RoughDuration::Unit::MONTHS:
492 _kdm_duration->SetRange(1, 12);
493 checked_set (_kdm_duration_unit, 2);
495 case RoughDuration::Unit::YEARS:
496 _kdm_duration->SetRange(1, 40);
497 checked_set (_kdm_duration_unit, 3);
501 setup_sensitivity ();
504 void kdm_duration_changed ()
506 auto config = Config::instance();
507 auto duration = _kdm_duration->GetValue();
508 RoughDuration::Unit unit = RoughDuration::Unit::DAYS;
509 switch (_kdm_duration_unit->GetSelection()) {
511 unit = RoughDuration::Unit::DAYS;
514 unit = RoughDuration::Unit::WEEKS;
517 unit = RoughDuration::Unit::MONTHS;
520 unit = RoughDuration::Unit::YEARS;
523 config->set_default_kdm_duration (RoughDuration(duration, unit));
526 void j2k_bandwidth_changed ()
528 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
531 void audio_delay_changed ()
533 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
536 void dcp_audio_channels_changed ()
538 int const s = _dcp_audio_channels->GetSelection ();
539 if (s != wxNOT_FOUND) {
540 Config::instance()->set_default_dcp_audio_channels (
541 locale_convert<int>(string_client_data(_dcp_audio_channels->GetClientObject(s)))
546 void directory_changed ()
548 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
551 void kdm_directory_changed ()
553 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
556 void kdm_type_changed ()
558 Config::instance()->set_default_kdm_type(_kdm_type->get());
561 void use_isdcf_name_by_default_changed ()
563 Config::instance()->set_use_isdcf_name_by_default (_use_isdcf_name_by_default->GetValue());
566 void still_length_changed ()
568 Config::instance()->set_default_still_length (_still_length->GetValue ());
571 void dcp_content_type_changed ()
573 auto ct = DCPContentType::all ();
574 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
577 void standard_changed ()
579 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
582 void metadata_changed ()
584 map<string, string> metadata;
585 for (auto const& i: _enable_metadata) {
586 if (i.second->GetValue()) {
587 metadata[i.first] = wx_to_std(_metadata[i.first]->GetValue());
590 Config::instance()->set_default_metadata (metadata);
591 setup_sensitivity ();
594 void enable_audio_language_toggled()
597 audio_language_changed();
600 void audio_language_changed()
602 if (_enable_audio_language->get()) {
603 Config::instance()->set_default_audio_language(_audio_language->get().get_value_or(dcp::LanguageTag("en-US")));
605 Config::instance()->unset_default_audio_language();
609 void enable_territory_toggled()
615 void territory_changed()
617 if (_enable_territory->get()) {
618 Config::instance()->set_default_territory(_territory->get().get_value_or(dcp::LanguageTag::RegionSubtag("US")));
620 Config::instance()->unset_default_territory();
624 void setup_sensitivity ()
626 _audio_language->enable(_enable_audio_language->get());
627 _territory->enable(_enable_territory->get());
628 for (auto const& i: _enable_metadata) {
629 _metadata[i.first]->Enable(i.second->GetValue());
633 wxSpinCtrl* _j2k_bandwidth;
634 wxSpinCtrl* _audio_delay;
635 wxSpinCtrl* _still_length;
636 #ifdef DCPOMATIC_USE_OWN_PICKER
637 DirPickerCtrl* _directory;
638 DirPickerCtrl* _kdm_directory;
640 wxDirPickerCtrl* _directory;
641 wxDirPickerCtrl* _kdm_directory;
643 KDMChoice* _kdm_type;
644 wxSpinCtrl* _kdm_duration;
645 wxChoice* _kdm_duration_unit;
646 CheckBox* _use_isdcf_name_by_default;
647 wxChoice* _dcp_content_type;
648 wxChoice* _dcp_audio_channels;
650 CheckBox* _enable_audio_language;
651 LanguageTagWidget* _audio_language;
652 CheckBox* _enable_territory;
653 RegionSubtagWidget* _territory;
654 map<string, CheckBox*> _enable_metadata;
655 map<string, wxTextCtrl*> _metadata;
659 class EncodingServersPage : public Page
662 EncodingServersPage (wxSize panel_size, int border)
663 : Page (panel_size, border)
666 wxString GetName () const override
672 wxBitmap GetLargeIcon () const override
674 return wxBitmap(icon_path("servers"), wxBITMAP_TYPE_PNG);
679 void setup () override
681 _use_any_servers = new CheckBox (_panel, _("Search network for servers"));
682 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
684 vector<EditableListColumn> columns;
685 columns.push_back (EditableListColumn(_("IP address / host name")));
686 _servers_list = new EditableList<string, ServerDialog> (
689 boost::bind (&Config::servers, Config::instance()),
690 boost::bind (&Config::set_servers, Config::instance(), _1),
691 boost::bind (&EncodingServersPage::server_column, this, _1),
692 EditableListTitle::INVISIBLE,
693 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
696 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
698 _use_any_servers->bind(&EncodingServersPage::use_any_servers_changed, this);
701 void config_changed () override
703 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
704 _servers_list->refresh ();
707 void use_any_servers_changed ()
709 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
712 string server_column (string s)
717 CheckBox* _use_any_servers;
718 EditableList<string, ServerDialog>* _servers_list;
722 class TMSPage : public Page
725 TMSPage (wxSize panel_size, int border)
726 : Page (panel_size, border)
729 wxString GetName () const override
735 wxBitmap GetLargeIcon () const override
737 return wxBitmap(icon_path("tms"), wxBITMAP_TYPE_PNG);
742 void setup () override
744 _upload = new CheckBox (_panel, _("Upload DCP to TMS after creation"));
745 _panel->GetSizer()->Add (_upload, 0, wxALL | wxEXPAND, _border);
747 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
748 table->AddGrowableCol (1, 1);
749 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
751 add_label_to_sizer (table, _panel, _("Protocol"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
752 _tms_protocol = new wxChoice (_panel, wxID_ANY);
753 table->Add (_tms_protocol, 1, wxEXPAND);
755 _tms_passive = new CheckBox(_panel, _("Passive mode"));
756 table->Add(_tms_passive, 1, wxEXPAND);
759 add_label_to_sizer (table, _panel, _("IP address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
760 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
761 table->Add (_tms_ip, 1, wxEXPAND);
763 add_label_to_sizer (table, _panel, _("Target path"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
764 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
765 table->Add (_tms_path, 1, wxEXPAND);
767 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
768 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
769 table->Add (_tms_user, 1, wxEXPAND);
771 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
772 _tms_password = new PasswordEntry (_panel);
773 table->Add (_tms_password->get_panel(), 1, wxEXPAND);
775 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
776 _tms_protocol->Append (_("FTP (for Dolby)"));
778 _upload->bind(&TMSPage::upload_changed, this);
779 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
780 _tms_passive->bind(&TMSPage::tms_passive_changed, this);
782 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
783 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
784 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
785 _tms_password->Changed.connect (boost::bind (&TMSPage::tms_password_changed, this));
788 void config_changed () override
790 auto config = Config::instance ();
792 checked_set (_upload, config->upload_after_make_dcp());
793 checked_set (_tms_protocol, static_cast<int>(config->tms_protocol()));
794 checked_set(_tms_passive, config->tms_protocol() == FileTransferProtocol::FTP && config->tms_passive());
795 checked_set (_tms_ip, config->tms_ip ());
796 checked_set (_tms_path, config->tms_path ());
797 checked_set (_tms_user, config->tms_user ());
798 checked_set (_tms_password, config->tms_password ());
800 _tms_passive->Enable(config->tms_protocol() == FileTransferProtocol::FTP);
803 void upload_changed ()
805 Config::instance()->set_upload_after_make_dcp (_upload->GetValue());
808 void tms_protocol_changed ()
810 Config::instance()->set_tms_protocol(static_cast<FileTransferProtocol>(_tms_protocol->GetSelection()));
813 void tms_passive_changed()
815 Config::instance()->set_tms_passive(_tms_passive->get());
818 void tms_ip_changed ()
820 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
823 void tms_path_changed ()
825 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
828 void tms_user_changed ()
830 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
833 void tms_password_changed ()
835 Config::instance()->set_tms_password (_tms_password->get());
839 CheckBox* _tms_passive;
840 wxChoice* _tms_protocol;
842 wxTextCtrl* _tms_path;
843 wxTextCtrl* _tms_user;
844 PasswordEntry* _tms_password;
848 class EmailPage : public Page
851 EmailPage (wxSize panel_size, int border)
852 : Page (panel_size, border)
855 wxString GetName () const override
861 wxBitmap GetLargeIcon () const override
863 return wxBitmap(icon_path("email"), wxBITMAP_TYPE_PNG);
868 void setup () override
870 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
871 table->AddGrowableCol (1, 1);
872 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
874 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
876 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
877 _server = new wxTextCtrl (_panel, wxID_ANY);
878 s->Add (_server, 1, wxEXPAND | wxALL);
879 add_label_to_sizer (s, _panel, _("port"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
880 _port = new wxSpinCtrl (_panel, wxID_ANY);
881 _port->SetRange (0, 65535);
883 add_label_to_sizer (s, _panel, _("protocol"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
884 _protocol = new wxChoice (_panel, wxID_ANY);
885 /* Make sure this matches the switches in config_changed and port_changed below */
886 _protocol->Append (_("Auto"));
887 _protocol->Append (_("Plain"));
888 _protocol->Append (_("STARTTLS"));
889 _protocol->Append (_("SSL"));
890 s->Add (_protocol, 1, wxALIGN_CENTER_VERTICAL);
891 table->Add (s, 1, wxEXPAND | wxALL);
894 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
895 _user = new wxTextCtrl (_panel, wxID_ANY);
896 table->Add (_user, 1, wxEXPAND | wxALL);
898 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
899 _password = new PasswordEntry (_panel);
900 table->Add (_password->get_panel(), 1, wxEXPAND | wxALL);
902 table->AddSpacer (0);
903 _send_test_email = new Button (_panel, _("Send test email..."));
904 table->Add (_send_test_email);
906 _server->Bind (wxEVT_TEXT, boost::bind(&EmailPage::server_changed, this));
907 _port->Bind (wxEVT_SPINCTRL, boost::bind(&EmailPage::port_changed, this));
908 _protocol->Bind (wxEVT_CHOICE, boost::bind(&EmailPage::protocol_changed, this));
909 _user->Bind (wxEVT_TEXT, boost::bind(&EmailPage::user_changed, this));
910 _password->Changed.connect (boost::bind(&EmailPage::password_changed, this));
911 _send_test_email->Bind (wxEVT_BUTTON, boost::bind(&EmailPage::send_test_email_clicked, this));
914 void config_changed () override
916 auto config = Config::instance ();
918 checked_set (_server, config->mail_server());
919 checked_set (_port, config->mail_port());
920 switch (config->mail_protocol()) {
921 case EmailProtocol::AUTO:
922 checked_set (_protocol, 0);
924 case EmailProtocol::PLAIN:
925 checked_set (_protocol, 1);
927 case EmailProtocol::STARTTLS:
928 checked_set (_protocol, 2);
930 case EmailProtocol::SSL:
931 checked_set (_protocol, 3);
934 checked_set (_user, config->mail_user());
935 checked_set (_password, config->mail_password());
938 void server_changed ()
940 Config::instance()->set_mail_server(wx_to_std(_server->GetValue()));
945 Config::instance()->set_mail_port(_port->GetValue());
948 void protocol_changed ()
950 switch (_protocol->GetSelection()) {
952 Config::instance()->set_mail_protocol(EmailProtocol::AUTO);
955 Config::instance()->set_mail_protocol(EmailProtocol::PLAIN);
958 Config::instance()->set_mail_protocol(EmailProtocol::STARTTLS);
961 Config::instance()->set_mail_protocol(EmailProtocol::SSL);
968 Config::instance()->set_mail_user (wx_to_std (_user->GetValue ()));
971 void password_changed ()
973 Config::instance()->set_mail_password(_password->get());
976 void send_test_email_clicked ()
978 SendTestEmailDialog dialog(_panel);
979 if (dialog.ShowModal() != wxID_OK) {
984 wx_to_std(dialog.from()),
985 { wx_to_std(dialog.to()) },
986 wx_to_std(_("DCP-o-matic test email")),
987 wx_to_std(_("This is a test email from DCP-o-matic."))
989 auto config = Config::instance();
991 email.send(config->mail_server(), config->mail_port(), config->mail_protocol(), config->mail_user(), config->mail_password());
992 } catch (NetworkError& e) {
993 error_dialog(_panel, std_to_wx(e.summary()), std_to_wx(e.detail().get_value_or("")));
995 } catch (std::exception& e) {
996 error_dialog(_panel, _("Test email sending failed."), std_to_wx(e.what()));
999 error_dialog(_panel, _("Test email sending failed."));
1002 message_dialog(_panel, _("Test email sent."));
1005 wxTextCtrl* _server;
1007 wxChoice* _protocol;
1009 PasswordEntry* _password;
1010 Button* _send_test_email;
1014 class KDMEmailPage : public Page
1018 KDMEmailPage (wxSize panel_size, int border)
1019 #ifdef DCPOMATIC_OSX
1020 /* We have to force both width and height of this one */
1021 : Page (wxSize (panel_size.GetWidth(), 128), border)
1023 : Page (panel_size, border)
1027 wxString GetName () const override
1029 return _("KDM Email");
1032 #ifdef DCPOMATIC_OSX
1033 wxBitmap GetLargeIcon () const override
1035 return wxBitmap(icon_path("kdm_email"), wxBITMAP_TYPE_PNG);
1040 void setup () override
1042 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1043 table->AddGrowableCol (1, 1);
1044 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1046 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1047 _subject = new wxTextCtrl (_panel, wxID_ANY);
1048 table->Add (_subject, 1, wxEXPAND | wxALL);
1050 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1051 _from = new wxTextCtrl (_panel, wxID_ANY);
1052 table->Add (_from, 1, wxEXPAND | wxALL);
1054 vector<EditableListColumn> columns;
1055 columns.push_back (EditableListColumn(_("Address")));
1056 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1057 _cc = new EditableList<string, EmailDialog> (
1060 bind (&Config::kdm_cc, Config::instance()),
1061 bind (&Config::set_kdm_cc, Config::instance(), _1),
1062 [] (string s, int) {
1065 EditableListTitle::VISIBLE,
1066 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
1068 table->Add (_cc, 1, wxEXPAND | wxALL);
1070 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1071 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1072 table->Add (_bcc, 1, wxEXPAND | wxALL);
1074 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1075 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1077 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1078 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1082 _subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1083 _from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1084 _bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1085 _email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1086 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_email, this));
1089 void config_changed () override
1091 auto config = Config::instance ();
1093 checked_set (_subject, config->kdm_subject ());
1094 checked_set (_from, config->kdm_from ());
1095 checked_set (_bcc, config->kdm_bcc ());
1096 checked_set (_email, Config::instance()->kdm_email ());
1099 void kdm_subject_changed ()
1101 Config::instance()->set_kdm_subject (wx_to_std (_subject->GetValue ()));
1104 void kdm_from_changed ()
1106 Config::instance()->set_kdm_from (wx_to_std (_from->GetValue ()));
1109 void kdm_bcc_changed ()
1111 Config::instance()->set_kdm_bcc (wx_to_std (_bcc->GetValue ()));
1114 void kdm_email_changed ()
1116 if (_email->GetValue().IsEmpty ()) {
1117 /* Sometimes we get sent an erroneous notification that the email
1118 is empty; I don't know why.
1122 Config::instance()->set_kdm_email (wx_to_std (_email->GetValue ()));
1127 Config::instance()->reset_kdm_email ();
1128 checked_set (_email, Config::instance()->kdm_email ());
1131 wxTextCtrl* _subject;
1133 EditableList<string, EmailDialog>* _cc;
1136 wxButton* _reset_email;
1140 class NotificationsPage : public Page
1143 NotificationsPage (wxSize panel_size, int border)
1144 #ifdef DCPOMATIC_OSX
1145 /* We have to force both width and height of this one */
1146 : Page (wxSize (panel_size.GetWidth(), 128), border)
1148 : Page (panel_size, border)
1152 wxString GetName () const override
1154 return _("Notifications");
1157 #ifdef DCPOMATIC_OSX
1158 wxBitmap GetLargeIcon () const override
1160 return wxBitmap(icon_path("notifications"), wxBITMAP_TYPE_PNG);
1165 void setup () override
1167 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1168 table->AddGrowableCol (1, 1);
1169 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1171 _enable_message_box = new CheckBox (_panel, _("Message box"));
1172 table->Add (_enable_message_box, 1, wxEXPAND | wxALL);
1173 table->AddSpacer (0);
1175 _enable_email = new CheckBox (_panel, _("Email"));
1176 table->Add (_enable_email, 1, wxEXPAND | wxALL);
1177 table->AddSpacer (0);
1179 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1180 _subject = new wxTextCtrl (_panel, wxID_ANY);
1181 table->Add (_subject, 1, wxEXPAND | wxALL);
1183 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1184 _from = new wxTextCtrl (_panel, wxID_ANY);
1185 table->Add (_from, 1, wxEXPAND | wxALL);
1187 add_label_to_sizer (table, _panel, _("To address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1188 _to = new wxTextCtrl (_panel, wxID_ANY);
1189 table->Add (_to, 1, wxEXPAND | wxALL);
1191 vector<EditableListColumn> columns;
1192 columns.push_back (EditableListColumn(_("Address")));
1193 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1194 _cc = new EditableList<string, EmailDialog> (
1197 bind (&Config::notification_cc, Config::instance()),
1198 bind (&Config::set_notification_cc, Config::instance(), _1),
1199 [] (string s, int) {
1202 EditableListTitle::VISIBLE,
1203 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
1205 table->Add (_cc, 1, wxEXPAND | wxALL);
1207 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1208 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1209 table->Add (_bcc, 1, wxEXPAND | wxALL);
1211 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1212 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1214 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1215 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1219 _enable_message_box->bind(&NotificationsPage::type_changed, this, _enable_message_box, Config::MESSAGE_BOX);
1220 _enable_email->bind(&NotificationsPage::type_changed, this, _enable_email, Config::EMAIL);
1222 _subject->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_subject_changed, this));
1223 _from->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_from_changed, this));
1224 _to->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_to_changed, this));
1225 _bcc->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_bcc_changed, this));
1226 _email->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_email_changed, this));
1227 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&NotificationsPage::reset_email, this));
1229 setup_sensitivity ();
1232 void setup_sensitivity ()
1234 bool const s = _enable_email->GetValue();
1235 _subject->Enable(s);
1241 _reset_email->Enable(s);
1244 void config_changed () override
1246 auto config = Config::instance ();
1248 checked_set (_enable_message_box, config->notification(Config::MESSAGE_BOX));
1249 checked_set (_enable_email, config->notification(Config::EMAIL));
1250 checked_set (_subject, config->notification_subject ());
1251 checked_set (_from, config->notification_from ());
1252 checked_set (_to, config->notification_to ());
1253 checked_set (_bcc, config->notification_bcc ());
1254 checked_set (_email, Config::instance()->notification_email ());
1256 setup_sensitivity ();
1259 void notification_subject_changed ()
1261 Config::instance()->set_notification_subject(wx_to_std(_subject->GetValue()));
1264 void notification_from_changed ()
1266 Config::instance()->set_notification_from(wx_to_std(_from->GetValue()));
1269 void notification_to_changed ()
1271 Config::instance()->set_notification_to(wx_to_std(_to->GetValue()));
1274 void notification_bcc_changed ()
1276 Config::instance()->set_notification_bcc(wx_to_std(_bcc->GetValue()));
1279 void notification_email_changed ()
1281 if (_email->GetValue().IsEmpty()) {
1282 /* Sometimes we get sent an erroneous notification that the email
1283 is empty; I don't know why.
1287 Config::instance()->set_notification_email(wx_to_std(_email->GetValue()));
1292 Config::instance()->reset_notification_email();
1293 checked_set (_email, Config::instance()->notification_email());
1296 void type_changed (CheckBox* b, Config::Notification n)
1298 Config::instance()->set_notification(n, b->GetValue());
1299 setup_sensitivity ();
1302 CheckBox* _enable_message_box;
1303 CheckBox* _enable_email;
1305 wxTextCtrl* _subject;
1308 EditableList<string, EmailDialog>* _cc;
1311 wxButton* _reset_email;
1315 class CoverSheetPage : public Page
1319 CoverSheetPage (wxSize panel_size, int border)
1320 #ifdef DCPOMATIC_OSX
1321 /* We have to force both width and height of this one */
1322 : Page (wxSize (panel_size.GetWidth(), 128), border)
1324 : Page (panel_size, border)
1328 wxString GetName () const override
1330 return _("Cover Sheet");
1333 #ifdef DCPOMATIC_OSX
1334 wxBitmap GetLargeIcon () const override
1336 return wxBitmap(icon_path("cover_sheet"), wxBITMAP_TYPE_PNG);
1341 void setup () override
1343 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1344 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
1346 _reset_cover_sheet = new Button (_panel, _("Reset to default text"));
1347 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
1349 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
1350 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
1353 void config_changed () override
1355 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1358 void cover_sheet_changed ()
1360 if (_cover_sheet->GetValue().IsEmpty ()) {
1361 /* Sometimes we get sent an erroneous notification that the cover sheet
1362 is empty; I don't know why.
1366 Config::instance()->set_cover_sheet(wx_to_std(_cover_sheet->GetValue()));
1369 void reset_cover_sheet ()
1371 Config::instance()->reset_cover_sheet();
1372 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1375 wxTextCtrl* _cover_sheet;
1376 wxButton* _reset_cover_sheet;
1380 class IdentifiersPage : public Page
1383 IdentifiersPage (wxSize panel_size, int border)
1384 : Page (panel_size, border)
1387 wxString GetName () const override
1389 return _("Identifiers");
1392 #ifdef DCPOMATIC_OSX
1393 wxBitmap GetLargeIcon () const override
1395 return wxBitmap(icon_path("identifiers"), wxBITMAP_TYPE_PNG);
1400 void setup () override
1402 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1403 table->AddGrowableCol (1, 1);
1405 add_label_to_sizer (table, _panel, _("Issuer"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1406 _issuer = new wxTextCtrl (_panel, wxID_ANY);
1407 _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."));
1408 table->Add (_issuer, 1, wxALL | wxEXPAND);
1410 add_label_to_sizer (table, _panel, _("Creator"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1411 _creator = new wxTextCtrl (_panel, wxID_ANY);
1412 _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."));
1413 table->Add (_creator, 1, wxALL | wxEXPAND);
1415 add_label_to_sizer (table, _panel, _("Company name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1416 _company_name = new wxTextCtrl (_panel, wxID_ANY);
1417 _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."));
1418 table->Add (_company_name, 1, wxALL | wxEXPAND);
1420 add_label_to_sizer (table, _panel, _("Product name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1421 _product_name = new wxTextCtrl (_panel, wxID_ANY);
1422 _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."));
1423 table->Add (_product_name, 1, wxALL | wxEXPAND);
1425 add_label_to_sizer (table, _panel, _("Product version"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1426 _product_version = new wxTextCtrl (_panel, wxID_ANY);
1427 _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."));
1428 table->Add (_product_version, 1, wxALL | wxEXPAND);
1430 add_label_to_sizer (table, _panel, _("JPEG2000 comment"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1431 _j2k_comment = new wxTextCtrl (_panel, wxID_ANY);
1432 _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."));
1433 table->Add (_j2k_comment, 1, wxALL | wxEXPAND);
1435 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1437 _issuer->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::issuer_changed, this));
1438 _creator->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::creator_changed, this));
1439 _company_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::company_name_changed, this));
1440 _product_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_name_changed, this));
1441 _product_version->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_version_changed, this));
1442 _j2k_comment->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::j2k_comment_changed, this));
1445 void config_changed () override
1447 auto config = Config::instance ();
1448 checked_set (_issuer, config->dcp_issuer ());
1449 checked_set (_creator, config->dcp_creator ());
1450 checked_set (_company_name, config->dcp_company_name ());
1451 checked_set (_product_name, config->dcp_product_name ());
1452 checked_set (_product_version, config->dcp_product_version ());
1453 checked_set (_j2k_comment, config->dcp_j2k_comment ());
1456 void issuer_changed ()
1458 Config::instance()->set_dcp_issuer(wx_to_std(_issuer->GetValue()));
1461 void creator_changed ()
1463 Config::instance()->set_dcp_creator(wx_to_std(_creator->GetValue()));
1466 void company_name_changed ()
1468 Config::instance()->set_dcp_company_name(wx_to_std(_company_name->GetValue()));
1471 void product_name_changed ()
1473 Config::instance()->set_dcp_product_name(wx_to_std(_product_name->GetValue()));
1476 void product_version_changed ()
1478 Config::instance()->set_dcp_product_version(wx_to_std(_product_version->GetValue()));
1481 void j2k_comment_changed ()
1483 Config::instance()->set_dcp_j2k_comment (wx_to_std(_j2k_comment->GetValue()));
1486 wxTextCtrl* _issuer;
1487 wxTextCtrl* _creator;
1488 wxTextCtrl* _company_name;
1489 wxTextCtrl* _product_name;
1490 wxTextCtrl* _product_version;
1491 wxTextCtrl* _j2k_comment;
1495 class NonStandardPage : public Page
1498 NonStandardPage(wxSize panel_size, int border)
1499 : Page(panel_size, border)
1502 wxString GetName() const override
1504 return _("Non-standard");
1507 #ifdef DCPOMATIC_OSX
1508 wxBitmap GetLargeIcon() const override
1510 return wxBitmap(icon_path("non_standard"), wxBITMAP_TYPE_PNG);
1515 void setup() override
1517 auto table = new wxFlexGridSizer(2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1518 table->AddGrowableCol(1, 1);
1519 _panel->GetSizer()->Add(table, 1, wxALL | wxEXPAND, _border);
1522 add_label_to_sizer(table, _panel, _("Maximum JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1523 auto s = new wxBoxSizer(wxHORIZONTAL);
1524 _maximum_j2k_bandwidth = new wxSpinCtrl(_panel);
1525 s->Add(_maximum_j2k_bandwidth, 1);
1526 add_label_to_sizer(s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxALIGN_CENTRE_VERTICAL);
1530 auto checkbox = [this, table](wxString name, CheckBox*& variable) {
1531 variable = new CheckBox(_panel, name);
1532 table->Add(variable, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1533 table->AddSpacer(0);
1536 checkbox(_("Allow any DCP frame rate"), _allow_any_dcp_frame_rate);
1538 _allow_any_container = new CheckBox(_panel, _("Allow full-frame and non-standard container ratios"));
1539 table->Add(_allow_any_container, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1540 auto restart = new StaticText(_panel, _("(restart DCP-o-matic to see all ratios)"));
1541 auto font = restart->GetFont();
1542 font.SetStyle(wxFONTSTYLE_ITALIC);
1543 font.SetPointSize(font.GetPointSize() - 1);
1544 restart->SetFont(font);
1545 table->Add(restart, 1, wxALIGN_CENTRE_VERTICAL | wxBOTTOM, DCPOMATIC_CHECKBOX_BOTTOM_PAD);
1546 restart->SetFont(font);
1548 checkbox(_("Allow creation of DCPs with 96kHz audio"), _allow_96khz_audio);
1549 checkbox(_("Allow mapping to all audio channels"), _use_all_audio_channels);
1550 checkbox(_("Allow use of SMPTE Bv2.0"), _allow_smpte_bv20);
1553 add_label_to_sizer(table, _panel, _("ISDCF name part length"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1554 auto s = new wxBoxSizer(wxHORIZONTAL);
1555 _isdcf_name_part_length = new wxSpinCtrl(_panel);
1556 s->Add(_isdcf_name_part_length, 1);
1560 _maximum_j2k_bandwidth->SetRange(1, 1000);
1561 _maximum_j2k_bandwidth->Bind(wxEVT_SPINCTRL, boost::bind(&NonStandardPage::maximum_j2k_bandwidth_changed, this));
1562 _allow_any_dcp_frame_rate->bind(&NonStandardPage::allow_any_dcp_frame_rate_changed, this);
1563 _allow_any_container->bind(&NonStandardPage::allow_any_container_changed, this);
1564 _allow_96khz_audio->bind(&NonStandardPage::allow_96khz_audio_changed, this);
1565 _use_all_audio_channels->bind(&NonStandardPage::use_all_channels_changed, this);
1566 _allow_smpte_bv20->bind(&NonStandardPage::allow_smpte_bv20_changed, this);
1567 _isdcf_name_part_length->SetRange(1, 256);
1568 _isdcf_name_part_length->Bind(wxEVT_SPINCTRL, boost::bind(&NonStandardPage::isdcf_name_part_length_changed, this));
1571 void config_changed() override
1573 auto config = Config::instance();
1575 checked_set(_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1576 checked_set(_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate());
1577 checked_set(_allow_any_container, config->allow_any_container());
1578 checked_set(_allow_96khz_audio, config->allow_96khz_audio());
1579 checked_set(_use_all_audio_channels, config->use_all_audio_channels());
1580 checked_set(_allow_smpte_bv20, config->allow_smpte_bv20());
1581 checked_set(_isdcf_name_part_length, config->isdcf_name_part_length());
1584 void maximum_j2k_bandwidth_changed()
1586 Config::instance()->set_maximum_j2k_bandwidth(_maximum_j2k_bandwidth->GetValue() * 1000000);
1589 void allow_any_dcp_frame_rate_changed()
1591 Config::instance()->set_allow_any_dcp_frame_rate(_allow_any_dcp_frame_rate->GetValue());
1594 void allow_any_container_changed()
1596 Config::instance()->set_allow_any_container(_allow_any_container->GetValue());
1599 void allow_96khz_audio_changed()
1601 Config::instance()->set_allow_96hhz_audio(_allow_96khz_audio->GetValue());
1604 void use_all_channels_changed()
1606 Config::instance()->set_use_all_audio_channels(_use_all_audio_channels->GetValue());
1609 void allow_smpte_bv20_changed()
1611 Config::instance()->set_allow_smpte_bv20(_allow_smpte_bv20->GetValue());
1614 void isdcf_name_part_length_changed()
1616 Config::instance()->set_isdcf_name_part_length(_isdcf_name_part_length->GetValue());
1619 wxSpinCtrl* _maximum_j2k_bandwidth = nullptr;
1620 CheckBox* _allow_any_dcp_frame_rate = nullptr;
1621 CheckBox* _allow_any_container = nullptr;
1622 CheckBox* _allow_96khz_audio = nullptr;
1623 CheckBox* _use_all_audio_channels = nullptr;
1624 CheckBox* _allow_smpte_bv20 = nullptr;
1625 wxSpinCtrl* _isdcf_name_part_length = nullptr;
1630 /** @class AdvancedPage
1631 * @brief Advanced page of the preferences dialog.
1633 class AdvancedPage : public Page
1636 AdvancedPage (wxSize panel_size, int border)
1637 : Page (panel_size, border)
1640 wxString GetName () const override
1642 return _("Advanced");
1645 #ifdef DCPOMATIC_OSX
1646 wxBitmap GetLargeIcon () const override
1648 return wxBitmap(icon_path("advanced"), wxBITMAP_TYPE_PNG);
1653 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1655 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1657 flags |= wxALIGN_RIGHT;
1660 wxStaticText* m = new StaticText (parent, text);
1661 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1664 void setup () override
1666 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1667 table->AddGrowableCol (1, 1);
1668 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1670 add_label_to_sizer (table, _panel, _("Video display mode"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1671 _video_display_mode = new wxChoice (_panel, wxID_ANY);
1672 table->Add (_video_display_mode);
1674 auto restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to change display mode)"), false);
1675 auto font = restart->GetFont();
1676 font.SetStyle (wxFONTSTYLE_ITALIC);
1677 font.SetPointSize (font.GetPointSize() - 1);
1678 restart->SetFont (font);
1679 table->AddSpacer (0);
1681 _show_experimental_audio_processors = new CheckBox (_panel, _("Show experimental audio processors"));
1682 table->Add (_show_experimental_audio_processors, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1683 table->AddSpacer (0);
1685 _only_servers_encode = new CheckBox (_panel, _("Only servers encode"));
1686 table->Add (_only_servers_encode, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1687 table->AddSpacer (0);
1690 add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1691 auto s = new wxBoxSizer (wxHORIZONTAL);
1692 _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
1693 s->Add (_frames_in_memory_multiplier, 1);
1698 auto format = create_label (_panel, _("DCP metadata filename format"), true);
1699 #ifdef DCPOMATIC_OSX
1700 auto align = new wxBoxSizer (wxHORIZONTAL);
1701 align->Add (format, 0, wxTOP, 2);
1702 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1704 table->Add (format, 0, wxTOP | wxLEFT | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1706 dcp::NameFormat::Map titles;
1707 titles['t'] = wx_to_std (_("type (cpl/pkl)"));
1708 dcp::NameFormat::Map examples;
1709 examples['t'] = "cpl";
1710 _dcp_metadata_filename_format = new NameFormatEditor (
1711 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1713 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1717 auto format = create_label (_panel, _("DCP asset filename format"), true);
1718 #ifdef DCPOMATIC_OSX
1719 auto align = new wxBoxSizer (wxHORIZONTAL);
1720 align->Add (format, 0, wxTOP, 2);
1721 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1723 table->Add (format, 0, wxTOP | wxLEFT | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1725 dcp::NameFormat::Map titles;
1726 titles['t'] = wx_to_std (_("type (j2c/pcm/sub)"));
1727 titles['r'] = wx_to_std (_("reel number"));
1728 titles['n'] = wx_to_std (_("number of reels"));
1729 titles['c'] = wx_to_std (_("content filename"));
1730 dcp::NameFormat::Map examples;
1731 examples['t'] = "j2c";
1732 examples['r'] = "1";
1733 examples['n'] = "4";
1734 examples['c'] = "myfile.mp4";
1735 _dcp_asset_filename_format = new NameFormatEditor (
1736 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1738 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1742 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1743 auto t = new wxFlexGridSizer (2);
1744 _log_general = new CheckBox (_panel, _("General"));
1745 t->Add (_log_general, 1, wxEXPAND | wxALL);
1746 _log_warning = new CheckBox (_panel, _("Warnings"));
1747 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1748 _log_error = new CheckBox (_panel, _("Errors"));
1749 t->Add (_log_error, 1, wxEXPAND | wxALL);
1750 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1751 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
1752 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1753 _log_debug_threed = new CheckBox (_panel, _("Debug: 3D"));
1754 t->Add (_log_debug_threed, 1, wxEXPAND | wxALL);
1755 _log_debug_encode = new CheckBox (_panel, _("Debug: encode"));
1756 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1757 _log_debug_email = new CheckBox (_panel, _("Debug: email sending"));
1758 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1759 _log_debug_video_view = new CheckBox (_panel, _("Debug: video view"));
1760 t->Add (_log_debug_video_view, 1, wxEXPAND | wxALL);
1761 _log_debug_player = new CheckBox (_panel, _("Debug: player"));
1762 t->Add (_log_debug_player, 1, wxEXPAND | wxALL);
1763 _log_debug_audio_analysis = new CheckBox (_panel, _("Debug: audio analysis"));
1764 t->Add (_log_debug_audio_analysis, 1, wxEXPAND | wxALL);
1765 table->Add (t, 0, wxALL, 6);
1768 #ifdef DCPOMATIC_WINDOWS
1769 _win32_console = new CheckBox (_panel, _("Open console window"));
1770 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1771 table->AddSpacer (0);
1774 _video_display_mode->Append (_("Simple (safer)"));
1775 #if wxCHECK_VERSION(3, 1, 0)
1776 _video_display_mode->Append (_("OpenGL (faster)"));
1778 _video_display_mode->Bind (wxEVT_CHOICE, boost::bind(&AdvancedPage::video_display_mode_changed, this));
1779 _show_experimental_audio_processors->bind(&AdvancedPage::show_experimental_audio_processors_changed, this);
1780 _only_servers_encode->bind(&AdvancedPage::only_servers_encode_changed, this);
1781 _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
1782 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1783 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1784 _log_general->bind(&AdvancedPage::log_changed, this);
1785 _log_warning->bind(&AdvancedPage::log_changed, this);
1786 _log_error->bind(&AdvancedPage::log_changed, this);
1787 _log_timing->bind(&AdvancedPage::log_changed, this);
1788 _log_debug_threed->bind(&AdvancedPage::log_changed, this);
1789 _log_debug_encode->bind(&AdvancedPage::log_changed, this);
1790 _log_debug_email->bind(&AdvancedPage::log_changed, this);
1791 _log_debug_video_view->bind(&AdvancedPage::log_changed, this);
1792 _log_debug_player->bind(&AdvancedPage::log_changed, this);
1793 _log_debug_audio_analysis->bind(&AdvancedPage::log_changed, this);
1794 #ifdef DCPOMATIC_WINDOWS
1795 _win32_console->bind(&AdvancedPage::win32_console_changed, this);
1799 void config_changed () override
1801 auto config = Config::instance ();
1803 switch (config->video_view_type()) {
1804 case Config::VIDEO_VIEW_SIMPLE:
1805 checked_set (_video_display_mode, 0);
1807 case Config::VIDEO_VIEW_OPENGL:
1808 checked_set (_video_display_mode, 1);
1811 checked_set (_show_experimental_audio_processors, config->show_experimental_audio_processors ());
1812 checked_set (_only_servers_encode, config->only_servers_encode ());
1813 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1814 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1815 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1816 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1817 checked_set (_log_debug_threed, config->log_types() & LogEntry::TYPE_DEBUG_THREE_D);
1818 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1819 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1820 checked_set (_log_debug_video_view, config->log_types() & LogEntry::TYPE_DEBUG_VIDEO_VIEW);
1821 checked_set (_log_debug_player, config->log_types() & LogEntry::TYPE_DEBUG_PLAYER);
1822 checked_set (_log_debug_audio_analysis, config->log_types() & LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS);
1823 checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
1824 #ifdef DCPOMATIC_WINDOWS
1825 checked_set (_win32_console, config->win32_console());
1829 void video_display_mode_changed ()
1831 if (_video_display_mode->GetSelection() == 0) {
1832 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_SIMPLE);
1834 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_OPENGL);
1838 void frames_in_memory_multiplier_changed ()
1840 Config::instance()->set_frames_in_memory_multiplier(_frames_in_memory_multiplier->GetValue());
1843 void show_experimental_audio_processors_changed ()
1845 Config::instance()->set_show_experimental_audio_processors(_show_experimental_audio_processors->GetValue());
1848 void only_servers_encode_changed ()
1850 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue());
1853 void dcp_metadata_filename_format_changed ()
1855 Config::instance()->set_dcp_metadata_filename_format(_dcp_metadata_filename_format->get());
1858 void dcp_asset_filename_format_changed ()
1860 Config::instance()->set_dcp_asset_filename_format(_dcp_asset_filename_format->get());
1866 if (_log_general->GetValue ()) {
1867 types |= LogEntry::TYPE_GENERAL;
1869 if (_log_warning->GetValue ()) {
1870 types |= LogEntry::TYPE_WARNING;
1872 if (_log_error->GetValue ()) {
1873 types |= LogEntry::TYPE_ERROR;
1875 if (_log_timing->GetValue ()) {
1876 types |= LogEntry::TYPE_TIMING;
1878 if (_log_debug_threed->GetValue ()) {
1879 types |= LogEntry::TYPE_DEBUG_THREE_D;
1881 if (_log_debug_encode->GetValue ()) {
1882 types |= LogEntry::TYPE_DEBUG_ENCODE;
1884 if (_log_debug_email->GetValue ()) {
1885 types |= LogEntry::TYPE_DEBUG_EMAIL;
1887 if (_log_debug_video_view->GetValue()) {
1888 types |= LogEntry::TYPE_DEBUG_VIDEO_VIEW;
1890 if (_log_debug_player->GetValue()) {
1891 types |= LogEntry::TYPE_DEBUG_PLAYER;
1893 if (_log_debug_audio_analysis->GetValue()) {
1894 types |= LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS;
1896 Config::instance()->set_log_types (types);
1899 #ifdef DCPOMATIC_WINDOWS
1900 void win32_console_changed ()
1902 Config::instance()->set_win32_console(_win32_console->GetValue());
1906 wxChoice* _video_display_mode = nullptr;
1907 wxSpinCtrl* _frames_in_memory_multiplier = nullptr;
1908 CheckBox* _show_experimental_audio_processors = nullptr;
1909 CheckBox* _only_servers_encode = nullptr;
1910 NameFormatEditor* _dcp_metadata_filename_format = nullptr;
1911 NameFormatEditor* _dcp_asset_filename_format = nullptr;
1912 CheckBox* _log_general = nullptr;
1913 CheckBox* _log_warning = nullptr;
1914 CheckBox* _log_error = nullptr;
1915 CheckBox* _log_timing = nullptr;
1916 CheckBox* _log_debug_threed = nullptr;
1917 CheckBox* _log_debug_encode = nullptr;
1918 CheckBox* _log_debug_email = nullptr;
1919 CheckBox* _log_debug_video_view = nullptr;
1920 CheckBox* _log_debug_player = nullptr;
1921 CheckBox* _log_debug_audio_analysis = nullptr;
1922 #ifdef DCPOMATIC_WINDOWS
1923 CheckBox* _win32_console = nullptr;
1928 wxPreferencesEditor*
1929 create_full_config_dialog ()
1931 auto e = new wxPreferencesEditor ();
1933 #ifdef DCPOMATIC_OSX
1934 /* Width that we force some of the config panels to be on OSX so that
1935 the containing window doesn't shrink too much when we select those panels.
1936 This is obviously an unpleasant hack.
1938 wxSize ps = wxSize(900, -1);
1939 int const border = 16;
1941 wxSize ps = wxSize (-1, -1);
1942 int const border = 8;
1945 e->AddPage (new FullGeneralPage (ps, border));
1946 e->AddPage (new SoundPage (ps, border));
1947 e->AddPage (new DefaultsPage (ps, border));
1948 e->AddPage (new EncodingServersPage(ps, border));
1949 e->AddPage (new KeysPage (ps, border));
1950 e->AddPage (new TMSPage (ps, border));
1951 e->AddPage (new EmailPage (ps, border));
1952 e->AddPage (new KDMEmailPage (ps, border));
1953 e->AddPage (new NotificationsPage (ps, border));
1954 e->AddPage (new CoverSheetPage (ps, border));
1955 e->AddPage (new IdentifiersPage (ps, border));
1956 e->AddPage (new NonStandardPage (ps, border));
1957 e->AddPage (new AdvancedPage (ps, border));