2 Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
6 DCP-o-matic is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 DCP-o-matic is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
22 /** @file src/full_config_dialog.cc
23 * @brief A dialogue to edit all DCP-o-matic configuration.
27 #include "check_box.h"
28 #include "config_dialog.h"
29 #include "config_move_dialog.h"
30 #include "dcpomatic_button.h"
31 #include "dcpomatic_choice.h"
32 #include "dir_picker_ctrl.h"
33 #include "editable_list.h"
34 #include "email_dialog.h"
35 #include "file_picker_ctrl.h"
36 #include "filter_dialog.h"
37 #include "full_config_dialog.h"
38 #include "kdm_choice.h"
39 #include "language_tag_widget.h"
40 #include "make_chain_dialog.h"
41 #include "nag_dialog.h"
42 #include "name_format_editor.h"
43 #include "password_entry.h"
44 #include "region_subtag_widget.h"
45 #include "send_test_email_dialog.h"
46 #include "server_dialog.h"
47 #include "static_text.h"
49 #include "grok/gpu_config_panel.h"
52 #include "wx_variant.h"
53 #include "lib/config.h"
54 #include "lib/cross.h"
55 #include "lib/dcp_content_type.h"
56 #include "lib/email.h"
57 #include "lib/exceptions.h"
58 #include "lib/filter.h"
60 #include "lib/ratio.h"
62 #include <dcp/certificate_chain.h>
63 #include <dcp/exceptions.h>
64 #include <dcp/filesystem.h>
65 #include <dcp/locale_convert.h>
66 #include <dcp/warnings.h>
67 LIBDCP_DISABLE_WARNINGS
68 #include <wx/filepicker.h>
69 #include <wx/preferences.h>
70 #include <wx/spinctrl.h>
71 #include <wx/stdpaths.h>
72 LIBDCP_ENABLE_WARNINGS
74 #include <boost/filesystem.hpp>
84 using std::shared_ptr;
88 using boost::optional;
89 #if BOOST_VERSION >= 106100
90 using namespace boost::placeholders;
92 using dcp::locale_convert;
95 class FullGeneralPage : public GeneralPage
98 FullGeneralPage (wxSize panel_size, int border)
99 : GeneralPage (panel_size, border)
103 void setup () override
105 auto table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
106 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
109 add_language_controls (table, r);
111 add_label_to_sizer(table, _panel, variant::wx::insert_dcpomatic(_("Number of threads %s should use")), true, wxGBPosition(r, 0));
112 _master_encoding_threads = new wxSpinCtrl (_panel);
113 table->Add (_master_encoding_threads, wxGBPosition (r, 1));
116 add_label_to_sizer(table, _panel, variant::wx::insert_dcpomatic_encode_server(_("Number of threads %s should use")), true, wxGBPosition(r, 0));
117 _server_encoding_threads = new wxSpinCtrl (_panel);
118 table->Add (_server_encoding_threads, wxGBPosition (r, 1));
121 add_label_to_sizer (table, _panel, _("Configuration file"), true, wxGBPosition (r, 0));
122 _config_file = new FilePickerCtrl(_panel, _("Select configuration file"), "*.xml", true, false, "ConfigFilePath");
123 table->Add (_config_file, wxGBPosition (r, 1));
126 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
127 _cinemas_file = new FilePickerCtrl(_panel, _("Select cinema and screen database file"), "*.xml", true, false, "CinemaDatabasePath");
128 table->Add (_cinemas_file, wxGBPosition (r, 1));
129 auto export_cinemas = new Button (_panel, _("Export..."));
130 table->Add (export_cinemas, wxGBPosition (r, 2));
133 add_label_to_sizer(table, _panel, _("Default \"add file\" location"), true, wxGBPosition(r, 0));
134 _default_add_file_location = new Choice(_panel);
135 table->Add(_default_add_file_location, wxGBPosition(r, 1));
138 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
139 _analyse_ebur128 = new CheckBox (_panel, _("Find integrated loudness, true peak and loudness range when analysing audio"));
140 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
144 _automatic_audio_analysis = new CheckBox (_panel, _("Automatically analyse content audio"));
145 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
148 add_update_controls (table, r);
150 _default_add_file_location->add_entry(_("Same place as last time"));
151 _default_add_file_location->add_entry(_("Same place as project"));
152 _default_add_file_location->bind(&FullGeneralPage::default_add_file_location_changed, this);
154 _config_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::config_file_changed, this));
155 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::cinemas_file_changed, this));
157 _master_encoding_threads->SetRange (1, 128);
158 _master_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::master_encoding_threads_changed, this));
159 _server_encoding_threads->SetRange (1, 128);
160 _server_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::server_encoding_threads_changed, this));
161 export_cinemas->Bind (wxEVT_BUTTON, boost::bind (&FullGeneralPage::export_cinemas_file, this));
163 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
164 _analyse_ebur128->bind(&FullGeneralPage::analyse_ebur128_changed, this);
166 _automatic_audio_analysis->bind(&FullGeneralPage::automatic_audio_analysis_changed, this);
169 void config_changed () override
171 auto config = Config::instance ();
173 checked_set (_master_encoding_threads, config->master_encoding_threads ());
174 checked_set (_server_encoding_threads, config->server_encoding_threads ());
175 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
176 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
178 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
179 checked_set (_config_file, config->config_read_file());
180 checked_set (_cinemas_file, config->cinemas_file());
181 checked_set(_default_add_file_location, config->default_add_file_location() == Config::DefaultAddFileLocation::SAME_AS_LAST_TIME ? 0 : 1);
183 GeneralPage::config_changed ();
186 void export_cinemas_file ()
189 _panel, _("Select Cinemas File"), wxEmptyString, wxEmptyString, wxT("XML files (*.xml)|*.xml"),
190 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
193 if (dialog.ShowModal() == wxID_OK) {
194 dcp::filesystem::copy_file(Config::instance()->cinemas_file(), wx_to_std(dialog.GetPath()), boost::filesystem::copy_option::overwrite_if_exists);
198 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
199 void analyse_ebur128_changed ()
201 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue());
205 void automatic_audio_analysis_changed ()
207 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue());
210 void master_encoding_threads_changed ()
212 Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue());
215 void server_encoding_threads_changed ()
217 Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue());
220 void config_file_changed ()
222 auto config = Config::instance();
223 auto const new_file = _config_file->path();
224 if (!new_file || *new_file == config->config_read_file()) {
227 bool copy_and_link = true;
228 if (dcp::filesystem::exists(*new_file)) {
229 ConfigMoveDialog dialog(_panel, *new_file);
230 if (dialog.ShowModal() == wxID_OK) {
231 copy_and_link = false;
237 if (new_file != config->config_read_file()) {
238 config->copy_and_link(*new_file);
241 config->link(*new_file);
245 void cinemas_file_changed ()
247 if (auto path = _cinemas_file->path()) {
248 Config::instance()->set_cinemas_file(*path);
252 void default_add_file_location_changed()
254 Config::instance()->set_default_add_file_location(
255 _default_add_file_location->get().get_value_or(0) == 0 ? Config::DefaultAddFileLocation::SAME_AS_LAST_TIME : Config::DefaultAddFileLocation::SAME_AS_PROJECT
259 Choice* _default_add_file_location;
260 wxSpinCtrl* _master_encoding_threads;
261 wxSpinCtrl* _server_encoding_threads;
262 FilePickerCtrl* _config_file;
263 FilePickerCtrl* _cinemas_file;
264 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
265 CheckBox* _analyse_ebur128;
267 CheckBox* _automatic_audio_analysis;
271 class DefaultsPage : public Page
274 DefaultsPage (wxSize panel_size, int border)
275 : Page (panel_size, border)
278 wxString GetName () const override
280 return _("Defaults");
284 wxBitmap GetLargeIcon () const override
286 return wxBitmap(icon_path("defaults"), wxBITMAP_TYPE_PNG);
291 void setup () override
293 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
294 table->AddGrowableCol (1, 1);
295 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
298 add_label_to_sizer (table, _panel, _("Default duration of still images"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
299 auto s = new wxBoxSizer (wxHORIZONTAL);
300 _still_length = new wxSpinCtrl (_panel);
301 s->Add (_still_length);
302 add_label_to_sizer (s, _panel, _("s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
306 add_label_to_sizer (table, _panel, _("Default directory for new films"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
307 #ifdef DCPOMATIC_USE_OWN_PICKER
308 _directory = new DirPickerCtrl (_panel);
310 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
312 table->Add (_directory, 1, wxEXPAND);
314 add_label_to_sizer (table, _panel, _("Default content type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
315 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
316 table->Add (_dcp_content_type);
318 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
319 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
320 table->Add (_dcp_audio_channels);
323 add_label_to_sizer(table, _panel, _("Default JPEG2000 bit rate"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
324 auto s = new wxBoxSizer (wxHORIZONTAL);
325 _j2k_video_bit_rate = new wxSpinCtrl(_panel);
326 s->Add(_j2k_video_bit_rate);
327 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
332 add_label_to_sizer(table, _panel, _("Default MPEG2 bit rate"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
333 auto s = new wxBoxSizer (wxHORIZONTAL);
334 _mpeg2_video_bit_rate = new wxSpinCtrl(_panel);
335 s->Add(_mpeg2_video_bit_rate);
336 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
341 add_label_to_sizer (table, _panel, _("Default audio delay"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
342 auto s = new wxBoxSizer (wxHORIZONTAL);
343 _audio_delay = new wxSpinCtrl (_panel);
344 s->Add (_audio_delay);
345 add_label_to_sizer (s, _panel, _("ms"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
349 add_label_to_sizer (table, _panel, _("Default standard"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
350 _standard = new wxChoice (_panel, wxID_ANY);
351 table->Add (_standard);
353 _enable_audio_language = new CheckBox(_panel, _("Default audio language"));
354 table->Add(_enable_audio_language, 1, wxEXPAND | wxALIGN_CENTRE_VERTICAL);
355 _audio_language = new LanguageTagWidget(_panel, _("Default audio language to use for new DCPs"), Config::instance()->default_audio_language(), wxString("cmnr-Hant-"));
356 table->Add(_audio_language->sizer());
358 _enable_territory = new CheckBox(_panel, _("Default territory"));
359 table->Add(_enable_territory, 1, wxEXPAND | wxALIGN_CENTRE_VERTICAL);
360 _territory = new RegionSubtagWidget(_panel, _("Default territory to use for new DCPs"), Config::instance()->default_territory(), wxString("cmnr-Hant-"));
361 table->Add(_territory->sizer());
363 table->Add (_enable_metadata["facility"] = new CheckBox (_panel, _("Default facility")), 0, wxALIGN_CENTRE_VERTICAL);
364 table->Add (_metadata["facility"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
366 table->Add (_enable_metadata["studio"] = new CheckBox (_panel, _("Default studio")), 0, wxALIGN_CENTRE_VERTICAL);
367 table->Add (_metadata["studio"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
369 table->Add (_enable_metadata["chain"] = new CheckBox (_panel, _("Default chain")), 0, wxALIGN_CENTRE_VERTICAL);
370 table->Add (_metadata["chain"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
372 table->Add (_enable_metadata["distributor"] = new CheckBox (_panel, _("Default distributor")), 0, wxALIGN_CENTRE_VERTICAL);
373 table->Add (_metadata["distributor"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
375 add_label_to_sizer (table, _panel, _("Default KDM directory"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
376 #ifdef DCPOMATIC_USE_OWN_PICKER
377 _kdm_directory = new DirPickerCtrl (_panel);
379 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
381 table->Add (_kdm_directory, 1, wxEXPAND);
383 add_label_to_sizer (table, _panel, _("Default KDM type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
384 _kdm_type = new KDMChoice (_panel);
385 table->Add (_kdm_type, 1, wxEXPAND);
387 add_label_to_sizer (table, _panel, _("Default KDM duration"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
388 _kdm_duration = new wxSpinCtrl (_panel);
389 _kdm_duration_unit = new wxChoice (_panel, wxID_ANY);
390 auto kdm_duration_sizer = new wxBoxSizer (wxHORIZONTAL);
391 kdm_duration_sizer->Add (_kdm_duration, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
392 kdm_duration_sizer->Add (_kdm_duration_unit, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
393 table->Add (kdm_duration_sizer, 1, wxEXPAND);
395 table->Add (_use_isdcf_name_by_default = new CheckBox(_panel, _("Use ISDCF name by default")), 0, wxALIGN_CENTRE_VERTICAL);
397 _still_length->SetRange (1, 3600);
398 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
400 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
401 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
402 _kdm_type->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_type_changed, this));
403 _kdm_duration_unit->Append (_("days"));
404 _kdm_duration_unit->Append (_("weeks"));
405 _kdm_duration_unit->Append (_("months"));
406 _kdm_duration_unit->Append (_("years"));
408 _kdm_duration->Bind (wxEVT_SPINCTRL, boost::bind(&DefaultsPage::kdm_duration_changed, this));
409 _kdm_duration_unit->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_duration_changed, this));
411 _use_isdcf_name_by_default->bind(&DefaultsPage::use_isdcf_name_by_default_changed, this);
413 for (auto i: DCPContentType::all()) {
414 _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
417 setup_audio_channels_choice (_dcp_audio_channels, 2);
419 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
420 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
422 _j2k_video_bit_rate->SetRange(50, 250);
423 _j2k_video_bit_rate->Bind(wxEVT_SPINCTRL, boost::bind(&DefaultsPage::j2k_video_bit_rate_changed, this));
424 _mpeg2_video_bit_rate->SetRange(1, 50);
425 _mpeg2_video_bit_rate->Bind(wxEVT_SPINCTRL, boost::bind(&DefaultsPage::mpeg2_video_bit_rate_changed, this));
427 _audio_delay->SetRange (-1000, 1000);
428 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
430 _standard->Append (_("SMPTE"));
431 _standard->Append (_("Interop"));
432 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
434 for (auto const& i: _enable_metadata) {
435 i.second->bind(&DefaultsPage::metadata_changed, this);
438 for (auto const& i: _metadata) {
439 i.second->Bind (wxEVT_TEXT, boost::bind(&DefaultsPage::metadata_changed, this));
442 _enable_audio_language->bind(&DefaultsPage::enable_audio_language_toggled, this);
443 _audio_language->Changed.connect(boost::bind(&DefaultsPage::audio_language_changed, this));
445 _enable_territory->bind(&DefaultsPage::enable_territory_toggled, this);
446 _territory->Changed.connect(boost::bind(&DefaultsPage::territory_changed, this));
449 void config_changed () override
451 auto config = Config::instance ();
453 auto const ct = DCPContentType::all ();
454 for (size_t i = 0; i < ct.size(); ++i) {
455 if (ct[i] == config->default_dcp_content_type()) {
456 _dcp_content_type->SetSelection (i);
460 checked_set (_still_length, config->default_still_length ());
461 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
462 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
463 _kdm_type->set (config->default_kdm_type());
464 checked_set (_use_isdcf_name_by_default, config->use_isdcf_name_by_default());
465 checked_set(_j2k_video_bit_rate, config->default_video_bit_rate(VideoEncoding::JPEG2000) / 1000000);
466 _j2k_video_bit_rate->SetRange(50, config->maximum_video_bit_rate(VideoEncoding::JPEG2000) / 1000000);
467 checked_set(_mpeg2_video_bit_rate, config->default_video_bit_rate(VideoEncoding::MPEG2) / 1000000);
468 _mpeg2_video_bit_rate->SetRange(1, config->maximum_video_bit_rate(VideoEncoding::MPEG2) / 1000000);
469 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
470 checked_set (_audio_delay, config->default_audio_delay ());
471 checked_set (_standard, config->default_interop() ? 1 : 0);
472 auto dal = config->default_audio_language();
473 checked_set(_enable_audio_language, static_cast<bool>(dal));
474 checked_set(_audio_language, dal ? dal : boost::none);
475 auto dt = config->default_territory();
476 checked_set(_enable_territory, static_cast<bool>(dt));
477 checked_set(_territory, dt ? dt : boost::none);
479 auto metadata = config->default_metadata();
481 for (auto const& i: metadata) {
482 _enable_metadata[i.first]->SetValue(true);
483 checked_set (_metadata[i.first], i.second);
486 for (auto const& i: _enable_metadata) {
487 if (metadata.find(i.first) == metadata.end()) {
488 checked_set (i.second, false);
492 for (auto const& i: _metadata) {
493 if (metadata.find(i.first) == metadata.end()) {
494 checked_set (i.second, wxT(""));
498 checked_set (_kdm_duration, config->default_kdm_duration().duration);
499 switch (config->default_kdm_duration().unit) {
500 case RoughDuration::Unit::DAYS:
501 _kdm_duration->SetRange(1, 365);
502 checked_set (_kdm_duration_unit, 0);
504 case RoughDuration::Unit::WEEKS:
505 _kdm_duration->SetRange(1, 52);
506 checked_set (_kdm_duration_unit, 1);
508 case RoughDuration::Unit::MONTHS:
509 _kdm_duration->SetRange(1, 12);
510 checked_set (_kdm_duration_unit, 2);
512 case RoughDuration::Unit::YEARS:
513 _kdm_duration->SetRange(1, 40);
514 checked_set (_kdm_duration_unit, 3);
518 setup_sensitivity ();
521 void kdm_duration_changed ()
523 auto config = Config::instance();
524 auto duration = _kdm_duration->GetValue();
525 RoughDuration::Unit unit = RoughDuration::Unit::DAYS;
526 switch (_kdm_duration_unit->GetSelection()) {
528 unit = RoughDuration::Unit::DAYS;
531 unit = RoughDuration::Unit::WEEKS;
534 unit = RoughDuration::Unit::MONTHS;
537 unit = RoughDuration::Unit::YEARS;
540 config->set_default_kdm_duration (RoughDuration(duration, unit));
543 void j2k_video_bit_rate_changed()
545 Config::instance()->set_default_video_bit_rate(VideoEncoding::JPEG2000, _j2k_video_bit_rate->GetValue() * 1000000);
548 void mpeg2_video_bit_rate_changed()
550 Config::instance()->set_default_video_bit_rate(VideoEncoding::MPEG2, _mpeg2_video_bit_rate->GetValue() * 1000000);
553 void audio_delay_changed ()
555 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
558 void dcp_audio_channels_changed ()
560 int const s = _dcp_audio_channels->GetSelection ();
561 if (s != wxNOT_FOUND) {
562 Config::instance()->set_default_dcp_audio_channels (
563 locale_convert<int>(string_client_data(_dcp_audio_channels->GetClientObject(s)))
568 void directory_changed ()
570 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
573 void kdm_directory_changed ()
575 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
578 void kdm_type_changed ()
580 Config::instance()->set_default_kdm_type(_kdm_type->get());
583 void use_isdcf_name_by_default_changed ()
585 Config::instance()->set_use_isdcf_name_by_default (_use_isdcf_name_by_default->GetValue());
588 void still_length_changed ()
590 Config::instance()->set_default_still_length (_still_length->GetValue ());
593 void dcp_content_type_changed ()
595 auto ct = DCPContentType::all ();
596 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
599 void standard_changed ()
601 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
604 void metadata_changed ()
606 map<string, string> metadata;
607 for (auto const& i: _enable_metadata) {
608 if (i.second->GetValue()) {
609 metadata[i.first] = wx_to_std(_metadata[i.first]->GetValue());
612 Config::instance()->set_default_metadata (metadata);
613 setup_sensitivity ();
616 void enable_audio_language_toggled()
619 audio_language_changed();
622 void audio_language_changed()
624 if (_enable_audio_language->get()) {
625 Config::instance()->set_default_audio_language(_audio_language->get().get_value_or(dcp::LanguageTag("en-US")));
627 Config::instance()->unset_default_audio_language();
631 void enable_territory_toggled()
637 void territory_changed()
639 if (_enable_territory->get()) {
640 Config::instance()->set_default_territory(_territory->get().get_value_or(dcp::LanguageTag::RegionSubtag("US")));
642 Config::instance()->unset_default_territory();
646 void setup_sensitivity ()
648 _audio_language->enable(_enable_audio_language->get());
649 _territory->enable(_enable_territory->get());
650 for (auto const& i: _enable_metadata) {
651 _metadata[i.first]->Enable(i.second->GetValue());
655 wxSpinCtrl* _j2k_video_bit_rate;
656 wxSpinCtrl* _mpeg2_video_bit_rate;
657 wxSpinCtrl* _audio_delay;
658 wxSpinCtrl* _still_length;
659 #ifdef DCPOMATIC_USE_OWN_PICKER
660 DirPickerCtrl* _directory;
661 DirPickerCtrl* _kdm_directory;
663 wxDirPickerCtrl* _directory;
664 wxDirPickerCtrl* _kdm_directory;
666 KDMChoice* _kdm_type;
667 wxSpinCtrl* _kdm_duration;
668 wxChoice* _kdm_duration_unit;
669 CheckBox* _use_isdcf_name_by_default;
670 wxChoice* _dcp_content_type;
671 wxChoice* _dcp_audio_channels;
673 CheckBox* _enable_audio_language;
674 LanguageTagWidget* _audio_language;
675 CheckBox* _enable_territory;
676 RegionSubtagWidget* _territory;
677 map<string, CheckBox*> _enable_metadata;
678 map<string, wxTextCtrl*> _metadata;
682 class EncodingServersPage : public Page
685 EncodingServersPage (wxSize panel_size, int border)
686 : Page (panel_size, border)
689 wxString GetName () const override
695 wxBitmap GetLargeIcon () const override
697 return wxBitmap(icon_path("servers"), wxBITMAP_TYPE_PNG);
702 void setup () override
704 _use_any_servers = new CheckBox (_panel, _("Search network for servers"));
705 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
707 vector<EditableListColumn> columns;
708 columns.push_back (EditableListColumn(_("IP address / host name")));
709 _servers_list = new EditableList<string, ServerDialog> (
712 boost::bind (&Config::servers, Config::instance()),
713 boost::bind (&Config::set_servers, Config::instance(), _1),
714 boost::bind (&EncodingServersPage::server_column, this, _1),
715 EditableListTitle::INVISIBLE,
716 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
719 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
721 _use_any_servers->bind(&EncodingServersPage::use_any_servers_changed, this);
724 void config_changed () override
726 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
727 _servers_list->refresh ();
730 void use_any_servers_changed ()
732 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
735 string server_column (string s)
740 CheckBox* _use_any_servers;
741 EditableList<string, ServerDialog>* _servers_list;
745 class TMSPage : public Page
748 TMSPage (wxSize panel_size, int border)
749 : Page (panel_size, border)
752 wxString GetName () const override
758 wxBitmap GetLargeIcon () const override
760 return wxBitmap(icon_path("tms"), wxBITMAP_TYPE_PNG);
765 void setup () override
767 _upload = new CheckBox (_panel, _("Upload DCP to TMS after creation"));
768 _panel->GetSizer()->Add (_upload, 0, wxALL | wxEXPAND, _border);
770 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
771 table->AddGrowableCol (1, 1);
772 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
774 add_label_to_sizer (table, _panel, _("Protocol"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
775 _tms_protocol = new wxChoice (_panel, wxID_ANY);
776 table->Add (_tms_protocol, 1, wxEXPAND);
778 _tms_passive = new CheckBox(_panel, _("Passive mode"));
779 table->Add(_tms_passive, 1, wxEXPAND);
782 add_label_to_sizer (table, _panel, _("IP address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
783 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
784 table->Add (_tms_ip, 1, wxEXPAND);
786 add_label_to_sizer (table, _panel, _("Target path"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
787 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
788 table->Add (_tms_path, 1, wxEXPAND);
790 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
791 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
792 table->Add (_tms_user, 1, wxEXPAND);
794 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
795 _tms_password = new PasswordEntry (_panel);
796 table->Add (_tms_password->get_panel(), 1, wxEXPAND);
798 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
799 _tms_protocol->Append (_("FTP (for Dolby)"));
801 _upload->bind(&TMSPage::upload_changed, this);
802 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
803 _tms_passive->bind(&TMSPage::tms_passive_changed, this);
805 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
806 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
807 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
808 _tms_password->Changed.connect (boost::bind (&TMSPage::tms_password_changed, this));
811 void config_changed () override
813 auto config = Config::instance ();
815 checked_set (_upload, config->upload_after_make_dcp());
816 checked_set (_tms_protocol, static_cast<int>(config->tms_protocol()));
817 checked_set(_tms_passive, config->tms_protocol() == FileTransferProtocol::FTP && config->tms_passive());
818 checked_set (_tms_ip, config->tms_ip ());
819 checked_set (_tms_path, config->tms_path ());
820 checked_set (_tms_user, config->tms_user ());
821 checked_set (_tms_password, config->tms_password ());
823 _tms_passive->Enable(config->tms_protocol() == FileTransferProtocol::FTP);
826 void upload_changed ()
828 Config::instance()->set_upload_after_make_dcp (_upload->GetValue());
831 void tms_protocol_changed ()
833 Config::instance()->set_tms_protocol(static_cast<FileTransferProtocol>(_tms_protocol->GetSelection()));
836 void tms_passive_changed()
838 Config::instance()->set_tms_passive(_tms_passive->get());
841 void tms_ip_changed ()
843 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
846 void tms_path_changed ()
848 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
851 void tms_user_changed ()
853 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
856 void tms_password_changed ()
858 Config::instance()->set_tms_password (_tms_password->get());
862 CheckBox* _tms_passive;
863 wxChoice* _tms_protocol;
865 wxTextCtrl* _tms_path;
866 wxTextCtrl* _tms_user;
867 PasswordEntry* _tms_password;
871 class EmailPage : public Page
874 EmailPage (wxSize panel_size, int border)
875 : Page (panel_size, border)
878 wxString GetName () const override
884 wxBitmap GetLargeIcon () const override
886 return wxBitmap(icon_path("email"), wxBITMAP_TYPE_PNG);
891 void setup () override
893 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
894 table->AddGrowableCol (1, 1);
895 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
897 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
899 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
900 _server = new wxTextCtrl (_panel, wxID_ANY);
901 s->Add (_server, 1, wxEXPAND | wxALL);
902 add_label_to_sizer (s, _panel, _("port"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
903 _port = new wxSpinCtrl (_panel, wxID_ANY);
904 _port->SetRange (0, 65535);
906 add_label_to_sizer (s, _panel, _("protocol"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
907 _protocol = new wxChoice (_panel, wxID_ANY);
908 /* Make sure this matches the switches in config_changed and port_changed below */
909 _protocol->Append (_("Auto"));
910 _protocol->Append (_("Plain"));
911 _protocol->Append (_("STARTTLS"));
912 _protocol->Append (_("SSL"));
913 s->Add (_protocol, 1, wxALIGN_CENTER_VERTICAL);
914 table->Add (s, 1, wxEXPAND | wxALL);
917 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
918 _user = new wxTextCtrl (_panel, wxID_ANY);
919 table->Add (_user, 1, wxEXPAND | wxALL);
921 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
922 _password = new PasswordEntry (_panel);
923 table->Add (_password->get_panel(), 1, wxEXPAND | wxALL);
925 table->AddSpacer (0);
926 _send_test_email = new Button (_panel, _("Send test email..."));
927 table->Add (_send_test_email);
929 _server->Bind (wxEVT_TEXT, boost::bind(&EmailPage::server_changed, this));
930 _port->Bind (wxEVT_SPINCTRL, boost::bind(&EmailPage::port_changed, this));
931 _protocol->Bind (wxEVT_CHOICE, boost::bind(&EmailPage::protocol_changed, this));
932 _user->Bind (wxEVT_TEXT, boost::bind(&EmailPage::user_changed, this));
933 _password->Changed.connect (boost::bind(&EmailPage::password_changed, this));
934 _send_test_email->Bind (wxEVT_BUTTON, boost::bind(&EmailPage::send_test_email_clicked, this));
937 void config_changed () override
939 auto config = Config::instance ();
941 checked_set (_server, config->mail_server());
942 checked_set (_port, config->mail_port());
943 switch (config->mail_protocol()) {
944 case EmailProtocol::AUTO:
945 checked_set (_protocol, 0);
947 case EmailProtocol::PLAIN:
948 checked_set (_protocol, 1);
950 case EmailProtocol::STARTTLS:
951 checked_set (_protocol, 2);
953 case EmailProtocol::SSL:
954 checked_set (_protocol, 3);
957 checked_set (_user, config->mail_user());
958 checked_set (_password, config->mail_password());
961 void server_changed ()
963 Config::instance()->set_mail_server(wx_to_std(_server->GetValue()));
968 Config::instance()->set_mail_port(_port->GetValue());
971 void protocol_changed ()
973 switch (_protocol->GetSelection()) {
975 Config::instance()->set_mail_protocol(EmailProtocol::AUTO);
978 Config::instance()->set_mail_protocol(EmailProtocol::PLAIN);
981 Config::instance()->set_mail_protocol(EmailProtocol::STARTTLS);
984 Config::instance()->set_mail_protocol(EmailProtocol::SSL);
991 Config::instance()->set_mail_user (wx_to_std (_user->GetValue ()));
994 void password_changed ()
996 Config::instance()->set_mail_password(_password->get());
999 void send_test_email_clicked ()
1001 SendTestEmailDialog dialog(_panel);
1002 if (dialog.ShowModal() != wxID_OK) {
1007 wx_to_std(dialog.from()),
1008 { wx_to_std(dialog.to()) },
1009 wx_to_std(variant::wx::insert_dcpomatic(_("%s test email"))),
1010 wx_to_std(variant::wx::insert_dcpomatic(_("This is a test email from %s.")))
1012 auto config = Config::instance();
1014 email.send(config->mail_server(), config->mail_port(), config->mail_protocol(), config->mail_user(), config->mail_password());
1015 } catch (NetworkError& e) {
1016 error_dialog(_panel, std_to_wx(e.summary()), std_to_wx(e.detail().get_value_or("")));
1018 } catch (std::exception& e) {
1019 error_dialog(_panel, _("Test email sending failed."), std_to_wx(e.what()));
1022 error_dialog(_panel, _("Test email sending failed."));
1025 message_dialog(_panel, _("Test email sent."));
1028 wxTextCtrl* _server;
1030 wxChoice* _protocol;
1032 PasswordEntry* _password;
1033 Button* _send_test_email;
1037 class KDMEmailPage : public Page
1041 KDMEmailPage (wxSize panel_size, int border)
1042 #ifdef DCPOMATIC_OSX
1043 /* We have to force both width and height of this one */
1044 : Page (wxSize (panel_size.GetWidth(), 128), border)
1046 : Page (panel_size, border)
1050 wxString GetName () const override
1052 return _("KDM Email");
1055 #ifdef DCPOMATIC_OSX
1056 wxBitmap GetLargeIcon () const override
1058 return wxBitmap(icon_path("kdm_email"), wxBITMAP_TYPE_PNG);
1063 void setup () override
1065 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1066 table->AddGrowableCol (1, 1);
1067 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1069 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1070 _subject = new wxTextCtrl (_panel, wxID_ANY);
1071 table->Add (_subject, 1, wxEXPAND | wxALL);
1073 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1074 _from = new wxTextCtrl (_panel, wxID_ANY);
1075 table->Add (_from, 1, wxEXPAND | wxALL);
1077 vector<EditableListColumn> columns;
1078 columns.push_back (EditableListColumn(_("Address")));
1079 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1080 _cc = new EditableList<string, EmailDialog> (
1083 bind (&Config::kdm_cc, Config::instance()),
1084 bind (&Config::set_kdm_cc, Config::instance(), _1),
1085 [] (string s, int) {
1088 EditableListTitle::VISIBLE,
1089 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
1091 table->Add (_cc, 1, wxEXPAND | wxALL);
1093 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1094 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1095 table->Add (_bcc, 1, wxEXPAND | wxALL);
1097 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1098 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1100 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1101 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1105 _subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1106 _from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1107 _bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1108 _email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1109 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_email, this));
1112 void config_changed () override
1114 auto config = Config::instance ();
1116 checked_set (_subject, config->kdm_subject ());
1117 checked_set (_from, config->kdm_from ());
1118 checked_set (_bcc, config->kdm_bcc ());
1119 checked_set (_email, Config::instance()->kdm_email ());
1122 void kdm_subject_changed ()
1124 Config::instance()->set_kdm_subject (wx_to_std (_subject->GetValue ()));
1127 void kdm_from_changed ()
1129 Config::instance()->set_kdm_from (wx_to_std (_from->GetValue ()));
1132 void kdm_bcc_changed ()
1134 Config::instance()->set_kdm_bcc (wx_to_std (_bcc->GetValue ()));
1137 void kdm_email_changed ()
1139 if (_email->GetValue().IsEmpty ()) {
1140 /* Sometimes we get sent an erroneous notification that the email
1141 is empty; I don't know why.
1145 Config::instance()->set_kdm_email (wx_to_std (_email->GetValue ()));
1150 Config::instance()->reset_kdm_email ();
1151 checked_set (_email, Config::instance()->kdm_email ());
1154 wxTextCtrl* _subject;
1156 EditableList<string, EmailDialog>* _cc;
1159 wxButton* _reset_email;
1163 class NotificationsPage : public Page
1166 NotificationsPage (wxSize panel_size, int border)
1167 #ifdef DCPOMATIC_OSX
1168 /* We have to force both width and height of this one */
1169 : Page (wxSize (panel_size.GetWidth(), 128), border)
1171 : Page (panel_size, border)
1175 wxString GetName () const override
1177 return _("Notifications");
1180 #ifdef DCPOMATIC_OSX
1181 wxBitmap GetLargeIcon () const override
1183 return wxBitmap(icon_path("notifications"), wxBITMAP_TYPE_PNG);
1188 void setup () override
1190 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1191 table->AddGrowableCol (1, 1);
1192 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1194 _enable_message_box = new CheckBox (_panel, _("Message box"));
1195 table->Add (_enable_message_box, 1, wxEXPAND | wxALL);
1196 table->AddSpacer (0);
1198 _enable_email = new CheckBox (_panel, _("Email"));
1199 table->Add (_enable_email, 1, wxEXPAND | wxALL);
1200 table->AddSpacer (0);
1202 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1203 _subject = new wxTextCtrl (_panel, wxID_ANY);
1204 table->Add (_subject, 1, wxEXPAND | wxALL);
1206 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1207 _from = new wxTextCtrl (_panel, wxID_ANY);
1208 table->Add (_from, 1, wxEXPAND | wxALL);
1210 add_label_to_sizer (table, _panel, _("To address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1211 _to = new wxTextCtrl (_panel, wxID_ANY);
1212 table->Add (_to, 1, wxEXPAND | wxALL);
1214 vector<EditableListColumn> columns;
1215 columns.push_back (EditableListColumn(_("Address")));
1216 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1217 _cc = new EditableList<string, EmailDialog> (
1220 bind (&Config::notification_cc, Config::instance()),
1221 bind (&Config::set_notification_cc, Config::instance(), _1),
1222 [] (string s, int) {
1225 EditableListTitle::VISIBLE,
1226 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
1228 table->Add (_cc, 1, wxEXPAND | wxALL);
1230 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1231 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1232 table->Add (_bcc, 1, wxEXPAND | wxALL);
1234 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1235 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1237 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1238 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1242 _enable_message_box->bind(&NotificationsPage::type_changed, this, _enable_message_box, Config::MESSAGE_BOX);
1243 _enable_email->bind(&NotificationsPage::type_changed, this, _enable_email, Config::EMAIL);
1245 _subject->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_subject_changed, this));
1246 _from->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_from_changed, this));
1247 _to->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_to_changed, this));
1248 _bcc->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_bcc_changed, this));
1249 _email->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_email_changed, this));
1250 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&NotificationsPage::reset_email, this));
1252 setup_sensitivity ();
1255 void setup_sensitivity ()
1257 bool const s = _enable_email->GetValue();
1258 _subject->Enable(s);
1264 _reset_email->Enable(s);
1267 void config_changed () override
1269 auto config = Config::instance ();
1271 checked_set (_enable_message_box, config->notification(Config::MESSAGE_BOX));
1272 checked_set (_enable_email, config->notification(Config::EMAIL));
1273 checked_set (_subject, config->notification_subject ());
1274 checked_set (_from, config->notification_from ());
1275 checked_set (_to, config->notification_to ());
1276 checked_set (_bcc, config->notification_bcc ());
1277 checked_set (_email, Config::instance()->notification_email ());
1279 setup_sensitivity ();
1282 void notification_subject_changed ()
1284 Config::instance()->set_notification_subject(wx_to_std(_subject->GetValue()));
1287 void notification_from_changed ()
1289 Config::instance()->set_notification_from(wx_to_std(_from->GetValue()));
1292 void notification_to_changed ()
1294 Config::instance()->set_notification_to(wx_to_std(_to->GetValue()));
1297 void notification_bcc_changed ()
1299 Config::instance()->set_notification_bcc(wx_to_std(_bcc->GetValue()));
1302 void notification_email_changed ()
1304 if (_email->GetValue().IsEmpty()) {
1305 /* Sometimes we get sent an erroneous notification that the email
1306 is empty; I don't know why.
1310 Config::instance()->set_notification_email(wx_to_std(_email->GetValue()));
1315 Config::instance()->reset_notification_email();
1316 checked_set (_email, Config::instance()->notification_email());
1319 void type_changed (CheckBox* b, Config::Notification n)
1321 Config::instance()->set_notification(n, b->GetValue());
1322 setup_sensitivity ();
1325 CheckBox* _enable_message_box;
1326 CheckBox* _enable_email;
1328 wxTextCtrl* _subject;
1331 EditableList<string, EmailDialog>* _cc;
1334 wxButton* _reset_email;
1338 class CoverSheetPage : public Page
1342 CoverSheetPage (wxSize panel_size, int border)
1343 #ifdef DCPOMATIC_OSX
1344 /* We have to force both width and height of this one */
1345 : Page (wxSize (panel_size.GetWidth(), 128), border)
1347 : Page (panel_size, border)
1351 wxString GetName () const override
1353 return _("Cover Sheet");
1356 #ifdef DCPOMATIC_OSX
1357 wxBitmap GetLargeIcon () const override
1359 return wxBitmap(icon_path("cover_sheet"), wxBITMAP_TYPE_PNG);
1364 void setup () override
1366 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1367 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
1369 _reset_cover_sheet = new Button (_panel, _("Reset to default text"));
1370 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
1372 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
1373 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
1376 void config_changed () override
1378 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1381 void cover_sheet_changed ()
1383 if (_cover_sheet->GetValue().IsEmpty ()) {
1384 /* Sometimes we get sent an erroneous notification that the cover sheet
1385 is empty; I don't know why.
1389 Config::instance()->set_cover_sheet(wx_to_std(_cover_sheet->GetValue()));
1392 void reset_cover_sheet ()
1394 Config::instance()->reset_cover_sheet();
1395 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1398 wxTextCtrl* _cover_sheet;
1399 wxButton* _reset_cover_sheet;
1403 class IdentifiersPage : public Page
1406 IdentifiersPage (wxSize panel_size, int border)
1407 : Page (panel_size, border)
1410 wxString GetName () const override
1412 return _("Identifiers");
1415 #ifdef DCPOMATIC_OSX
1416 wxBitmap GetLargeIcon () const override
1418 return wxBitmap(icon_path("identifiers"), wxBITMAP_TYPE_PNG);
1423 void setup () override
1425 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1426 table->AddGrowableCol (1, 1);
1428 add_label_to_sizer (table, _panel, _("Issuer"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1429 _issuer = new wxTextCtrl (_panel, wxID_ANY);
1430 _issuer->SetToolTip(
1431 variant::wx::insert_dcpomatic(
1432 _("This will be written to the DCP's XML files as the <Issuer>. If it is blank, a default value mentioning %s will be used.")
1434 table->Add (_issuer, 1, wxALL | wxEXPAND);
1436 add_label_to_sizer (table, _panel, _("Creator"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1437 _creator = new wxTextCtrl (_panel, wxID_ANY);
1438 _creator->SetToolTip(
1439 variant::wx::insert_dcpomatic(
1440 _("This will be written to the DCP's XML files as the <Creator>. If it is blank, a default value mentioning %s will be used.")
1442 table->Add (_creator, 1, wxALL | wxEXPAND);
1444 add_label_to_sizer (table, _panel, _("Company name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1445 _company_name = new wxTextCtrl (_panel, wxID_ANY);
1446 _company_name->SetToolTip(
1447 variant::wx::insert_dcpomatic(
1448 _("This will be written to the DCP's MXF files as the 'company name'. If it is blank, a default value mentioning libdcp (an internal %s library) will be used.")
1450 table->Add (_company_name, 1, wxALL | wxEXPAND);
1452 add_label_to_sizer (table, _panel, _("Product name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1453 _product_name = new wxTextCtrl (_panel, wxID_ANY);
1454 _product_name->SetToolTip(
1455 variant::wx::insert_dcpomatic(
1456 _("This will be written to the DCP's MXF files as the 'product name'. If it is blank, a default value mentioning libdcp (an internal %s library) will be used.")
1458 table->Add (_product_name, 1, wxALL | wxEXPAND);
1460 add_label_to_sizer (table, _panel, _("Product version"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1461 _product_version = new wxTextCtrl (_panel, wxID_ANY);
1462 _product_version->SetToolTip(
1463 variant::wx::insert_dcpomatic(
1464 _("This will be written to the DCP's MXF files as the 'product version'. If it is blank, a default value mentioning libdcp (an internal %s library) will be used.")
1466 table->Add (_product_version, 1, wxALL | wxEXPAND);
1468 add_label_to_sizer (table, _panel, _("JPEG2000 comment"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1469 _j2k_comment = new wxTextCtrl (_panel, wxID_ANY);
1470 _j2k_comment->SetToolTip(
1471 variant::wx::insert_dcpomatic(
1472 _("This will be written to the DCP's JPEG2000 data as a comment. If it is blank, a default value mentioning libdcp (an internal %s library) will be used.")
1474 table->Add (_j2k_comment, 1, wxALL | wxEXPAND);
1476 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1478 _issuer->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::issuer_changed, this));
1479 _creator->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::creator_changed, this));
1480 _company_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::company_name_changed, this));
1481 _product_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_name_changed, this));
1482 _product_version->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_version_changed, this));
1483 _j2k_comment->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::j2k_comment_changed, this));
1486 void config_changed () override
1488 auto config = Config::instance ();
1489 checked_set (_issuer, config->dcp_issuer ());
1490 checked_set (_creator, config->dcp_creator ());
1491 checked_set (_company_name, config->dcp_company_name ());
1492 checked_set (_product_name, config->dcp_product_name ());
1493 checked_set (_product_version, config->dcp_product_version ());
1494 checked_set (_j2k_comment, config->dcp_j2k_comment ());
1497 void issuer_changed ()
1499 Config::instance()->set_dcp_issuer(wx_to_std(_issuer->GetValue()));
1502 void creator_changed ()
1504 Config::instance()->set_dcp_creator(wx_to_std(_creator->GetValue()));
1507 void company_name_changed ()
1509 Config::instance()->set_dcp_company_name(wx_to_std(_company_name->GetValue()));
1512 void product_name_changed ()
1514 Config::instance()->set_dcp_product_name(wx_to_std(_product_name->GetValue()));
1517 void product_version_changed ()
1519 Config::instance()->set_dcp_product_version(wx_to_std(_product_version->GetValue()));
1522 void j2k_comment_changed ()
1524 Config::instance()->set_dcp_j2k_comment (wx_to_std(_j2k_comment->GetValue()));
1527 wxTextCtrl* _issuer;
1528 wxTextCtrl* _creator;
1529 wxTextCtrl* _company_name;
1530 wxTextCtrl* _product_name;
1531 wxTextCtrl* _product_version;
1532 wxTextCtrl* _j2k_comment;
1536 class NonStandardPage : public Page
1539 NonStandardPage(wxSize panel_size, int border)
1540 : Page(panel_size, border)
1543 wxString GetName() const override
1545 return _("Non-standard");
1548 #ifdef DCPOMATIC_OSX
1549 wxBitmap GetLargeIcon() const override
1551 return wxBitmap(icon_path("non_standard"), wxBITMAP_TYPE_PNG);
1556 void setup() override
1558 auto table = new wxFlexGridSizer(2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1559 table->AddGrowableCol(1, 1);
1560 _panel->GetSizer()->Add(table, 1, wxALL | wxEXPAND, _border);
1563 add_label_to_sizer(table, _panel, _("Maximum JPEG2000 bit rate"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1564 auto s = new wxBoxSizer(wxHORIZONTAL);
1565 _maximum_j2k_video_bit_rate = new wxSpinCtrl(_panel);
1566 s->Add(_maximum_j2k_video_bit_rate, 1);
1567 add_label_to_sizer(s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxALIGN_CENTRE_VERTICAL);
1572 add_label_to_sizer(table, _panel, _("Maximum MPEG2 bit rate"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1573 auto s = new wxBoxSizer(wxHORIZONTAL);
1574 _maximum_mpeg2_video_bit_rate = new wxSpinCtrl(_panel);
1575 s->Add(_maximum_mpeg2_video_bit_rate, 1);
1576 add_label_to_sizer(s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxALIGN_CENTRE_VERTICAL);
1580 auto checkbox = [this, table](wxString name, CheckBox*& variable) {
1581 variable = new CheckBox(_panel, name);
1582 table->Add(variable, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1583 table->AddSpacer(0);
1586 checkbox(_("Allow any DCP frame rate"), _allow_any_dcp_frame_rate);
1588 _allow_any_container = new CheckBox(_panel, _("Allow full-frame and non-standard container ratios"));
1589 table->Add(_allow_any_container, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1590 table->AddSpacer(0);
1592 checkbox(_("Allow creation of DCPs with 96kHz audio"), _allow_96khz_audio);
1593 checkbox(_("Allow mapping to all audio channels"), _use_all_audio_channels);
1594 checkbox(_("Allow use of SMPTE Bv2.0"), _allow_smpte_bv20);
1597 add_label_to_sizer(table, _panel, _("ISDCF name part length"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1598 auto s = new wxBoxSizer(wxHORIZONTAL);
1599 _isdcf_name_part_length = new wxSpinCtrl(_panel);
1600 s->Add(_isdcf_name_part_length, 1);
1604 _maximum_j2k_video_bit_rate->SetRange(1, 1000);
1605 _maximum_j2k_video_bit_rate->Bind(wxEVT_SPINCTRL, boost::bind(&NonStandardPage::maximum_j2k_video_bit_rate_changed, this));
1606 _maximum_mpeg2_video_bit_rate->SetRange(1, 100);
1607 _maximum_mpeg2_video_bit_rate->Bind(wxEVT_SPINCTRL, boost::bind(&NonStandardPage::maximum_mpeg2_video_bit_rate_changed, this));
1608 _allow_any_dcp_frame_rate->bind(&NonStandardPage::allow_any_dcp_frame_rate_changed, this);
1609 _allow_any_container->bind(&NonStandardPage::allow_any_container_changed, this);
1610 _allow_96khz_audio->bind(&NonStandardPage::allow_96khz_audio_changed, this);
1611 _use_all_audio_channels->bind(&NonStandardPage::use_all_channels_changed, this);
1612 _allow_smpte_bv20->bind(&NonStandardPage::allow_smpte_bv20_changed, this);
1613 _isdcf_name_part_length->SetRange(1, 256);
1614 _isdcf_name_part_length->Bind(wxEVT_SPINCTRL, boost::bind(&NonStandardPage::isdcf_name_part_length_changed, this));
1617 void config_changed() override
1619 auto config = Config::instance();
1621 checked_set(_maximum_j2k_video_bit_rate, config->maximum_video_bit_rate(VideoEncoding::JPEG2000) / 1000000);
1622 checked_set(_maximum_mpeg2_video_bit_rate, config->maximum_video_bit_rate(VideoEncoding::MPEG2) / 1000000);
1623 checked_set(_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate());
1624 checked_set(_allow_any_container, config->allow_any_container());
1625 checked_set(_allow_96khz_audio, config->allow_96khz_audio());
1626 checked_set(_use_all_audio_channels, config->use_all_audio_channels());
1627 checked_set(_allow_smpte_bv20, config->allow_smpte_bv20());
1628 checked_set(_isdcf_name_part_length, config->isdcf_name_part_length());
1631 void maximum_j2k_video_bit_rate_changed()
1633 Config::instance()->set_maximum_video_bit_rate(VideoEncoding::JPEG2000, _maximum_j2k_video_bit_rate->GetValue() * 1000000);
1636 void maximum_mpeg2_video_bit_rate_changed()
1638 Config::instance()->set_maximum_video_bit_rate(VideoEncoding::MPEG2, _maximum_mpeg2_video_bit_rate->GetValue() * 1000000);
1641 void allow_any_dcp_frame_rate_changed()
1643 Config::instance()->set_allow_any_dcp_frame_rate(_allow_any_dcp_frame_rate->GetValue());
1646 void allow_any_container_changed()
1648 Config::instance()->set_allow_any_container(_allow_any_container->GetValue());
1651 void allow_96khz_audio_changed()
1653 Config::instance()->set_allow_96hhz_audio(_allow_96khz_audio->GetValue());
1656 void use_all_channels_changed()
1658 Config::instance()->set_use_all_audio_channels(_use_all_audio_channels->GetValue());
1661 void allow_smpte_bv20_changed()
1663 Config::instance()->set_allow_smpte_bv20(_allow_smpte_bv20->GetValue());
1666 void isdcf_name_part_length_changed()
1668 Config::instance()->set_isdcf_name_part_length(_isdcf_name_part_length->GetValue());
1671 wxSpinCtrl* _maximum_j2k_video_bit_rate = nullptr;
1672 wxSpinCtrl* _maximum_mpeg2_video_bit_rate = nullptr;
1673 CheckBox* _allow_any_dcp_frame_rate = nullptr;
1674 CheckBox* _allow_any_container = nullptr;
1675 CheckBox* _allow_96khz_audio = nullptr;
1676 CheckBox* _use_all_audio_channels = nullptr;
1677 CheckBox* _allow_smpte_bv20 = nullptr;
1678 wxSpinCtrl* _isdcf_name_part_length = nullptr;
1683 /** @class AdvancedPage
1684 * @brief Advanced page of the preferences dialog.
1686 class AdvancedPage : public Page
1689 AdvancedPage (wxSize panel_size, int border)
1690 : Page (panel_size, border)
1693 wxString GetName () const override
1695 return _("Advanced");
1698 #ifdef DCPOMATIC_OSX
1699 wxBitmap GetLargeIcon () const override
1701 return wxBitmap(icon_path("advanced"), wxBITMAP_TYPE_PNG);
1706 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1708 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1710 flags |= wxALIGN_RIGHT;
1713 wxStaticText* m = new StaticText (parent, text);
1714 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1717 void setup () override
1719 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1720 table->AddGrowableCol (1, 1);
1721 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1723 add_label_to_sizer (table, _panel, _("Video display mode"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1724 _video_display_mode = new wxChoice (_panel, wxID_ANY);
1725 table->Add (_video_display_mode);
1727 auto restart = add_label_to_sizer(table, _panel, variant::wx::insert_dcpomatic(_("(restart %s to change display mode)")), false);
1728 auto font = restart->GetFont();
1729 font.SetStyle (wxFONTSTYLE_ITALIC);
1730 font.SetPointSize (font.GetPointSize() - 1);
1731 restart->SetFont (font);
1732 table->AddSpacer (0);
1734 _show_experimental_audio_processors = new CheckBox (_panel, _("Show experimental audio processors"));
1735 table->Add (_show_experimental_audio_processors, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1736 table->AddSpacer (0);
1738 _only_servers_encode = new CheckBox (_panel, _("Only servers encode"));
1739 table->Add (_only_servers_encode, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1740 table->AddSpacer (0);
1743 add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1744 auto s = new wxBoxSizer (wxHORIZONTAL);
1745 _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
1746 s->Add (_frames_in_memory_multiplier, 1);
1751 auto format = create_label (_panel, _("DCP metadata filename format"), true);
1752 #ifdef DCPOMATIC_OSX
1753 auto align = new wxBoxSizer (wxHORIZONTAL);
1754 align->Add (format, 0, wxTOP, 2);
1755 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1757 table->Add (format, 0, wxTOP | wxLEFT | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1759 dcp::NameFormat::Map titles;
1760 titles['t'] = wx_to_std (_("type (cpl/pkl)"));
1761 dcp::NameFormat::Map examples;
1762 examples['t'] = "cpl";
1763 _dcp_metadata_filename_format = new NameFormatEditor (
1764 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1766 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1770 auto format = create_label (_panel, _("DCP asset filename format"), true);
1771 #ifdef DCPOMATIC_OSX
1772 auto align = new wxBoxSizer (wxHORIZONTAL);
1773 align->Add (format, 0, wxTOP, 2);
1774 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1776 table->Add (format, 0, wxTOP | wxLEFT | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1778 dcp::NameFormat::Map titles;
1779 titles['t'] = wx_to_std (_("type (j2c/pcm/sub)"));
1780 titles['r'] = wx_to_std (_("reel number"));
1781 titles['n'] = wx_to_std (_("number of reels"));
1782 titles['c'] = wx_to_std (_("content filename"));
1783 dcp::NameFormat::Map examples;
1784 examples['t'] = "j2c";
1785 examples['r'] = "1";
1786 examples['n'] = "4";
1787 examples['c'] = "myfile.mp4";
1788 _dcp_asset_filename_format = new NameFormatEditor (
1789 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1791 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1795 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1796 auto t = new wxFlexGridSizer (2);
1797 _log_general = new CheckBox (_panel, _("General"));
1798 t->Add (_log_general, 1, wxEXPAND | wxALL);
1799 _log_warning = new CheckBox (_panel, _("Warnings"));
1800 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1801 _log_error = new CheckBox (_panel, _("Errors"));
1802 t->Add (_log_error, 1, wxEXPAND | wxALL);
1803 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1804 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
1805 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1806 _log_debug_threed = new CheckBox (_panel, _("Debug: 3D"));
1807 t->Add (_log_debug_threed, 1, wxEXPAND | wxALL);
1808 _log_debug_encode = new CheckBox (_panel, _("Debug: encode"));
1809 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1810 _log_debug_email = new CheckBox (_panel, _("Debug: email sending"));
1811 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1812 _log_debug_video_view = new CheckBox (_panel, _("Debug: video view"));
1813 t->Add (_log_debug_video_view, 1, wxEXPAND | wxALL);
1814 _log_debug_player = new CheckBox (_panel, _("Debug: player"));
1815 t->Add (_log_debug_player, 1, wxEXPAND | wxALL);
1816 _log_debug_audio_analysis = new CheckBox (_panel, _("Debug: audio analysis"));
1817 t->Add (_log_debug_audio_analysis, 1, wxEXPAND | wxALL);
1818 table->Add (t, 0, wxALL, 6);
1821 #ifdef DCPOMATIC_WINDOWS
1822 _win32_console = new CheckBox (_panel, _("Open console window"));
1823 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1824 table->AddSpacer (0);
1827 _video_display_mode->Append (_("Simple (safer)"));
1828 #if wxCHECK_VERSION(3, 1, 0)
1829 _video_display_mode->Append (_("OpenGL (faster)"));
1831 _video_display_mode->Bind (wxEVT_CHOICE, boost::bind(&AdvancedPage::video_display_mode_changed, this));
1832 _show_experimental_audio_processors->bind(&AdvancedPage::show_experimental_audio_processors_changed, this);
1833 _only_servers_encode->bind(&AdvancedPage::only_servers_encode_changed, this);
1834 _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
1835 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1836 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1837 _log_general->bind(&AdvancedPage::log_changed, this);
1838 _log_warning->bind(&AdvancedPage::log_changed, this);
1839 _log_error->bind(&AdvancedPage::log_changed, this);
1840 _log_timing->bind(&AdvancedPage::log_changed, this);
1841 _log_debug_threed->bind(&AdvancedPage::log_changed, this);
1842 _log_debug_encode->bind(&AdvancedPage::log_changed, this);
1843 _log_debug_email->bind(&AdvancedPage::log_changed, this);
1844 _log_debug_video_view->bind(&AdvancedPage::log_changed, this);
1845 _log_debug_player->bind(&AdvancedPage::log_changed, this);
1846 _log_debug_audio_analysis->bind(&AdvancedPage::log_changed, this);
1847 #ifdef DCPOMATIC_WINDOWS
1848 _win32_console->bind(&AdvancedPage::win32_console_changed, this);
1852 void config_changed () override
1854 auto config = Config::instance ();
1856 switch (config->video_view_type()) {
1857 case Config::VIDEO_VIEW_SIMPLE:
1858 checked_set (_video_display_mode, 0);
1860 case Config::VIDEO_VIEW_OPENGL:
1861 checked_set (_video_display_mode, 1);
1864 checked_set (_show_experimental_audio_processors, config->show_experimental_audio_processors ());
1865 checked_set (_only_servers_encode, config->only_servers_encode ());
1866 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1867 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1868 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1869 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1870 checked_set (_log_debug_threed, config->log_types() & LogEntry::TYPE_DEBUG_THREE_D);
1871 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1872 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1873 checked_set (_log_debug_video_view, config->log_types() & LogEntry::TYPE_DEBUG_VIDEO_VIEW);
1874 checked_set (_log_debug_player, config->log_types() & LogEntry::TYPE_DEBUG_PLAYER);
1875 checked_set (_log_debug_audio_analysis, config->log_types() & LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS);
1876 checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
1877 #ifdef DCPOMATIC_WINDOWS
1878 checked_set (_win32_console, config->win32_console());
1882 void video_display_mode_changed ()
1884 if (_video_display_mode->GetSelection() == 0) {
1885 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_SIMPLE);
1887 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_OPENGL);
1891 void frames_in_memory_multiplier_changed ()
1893 Config::instance()->set_frames_in_memory_multiplier(_frames_in_memory_multiplier->GetValue());
1896 void show_experimental_audio_processors_changed ()
1898 Config::instance()->set_show_experimental_audio_processors(_show_experimental_audio_processors->GetValue());
1901 void only_servers_encode_changed ()
1903 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue());
1906 void dcp_metadata_filename_format_changed ()
1908 Config::instance()->set_dcp_metadata_filename_format(_dcp_metadata_filename_format->get());
1911 void dcp_asset_filename_format_changed ()
1913 Config::instance()->set_dcp_asset_filename_format(_dcp_asset_filename_format->get());
1919 if (_log_general->GetValue ()) {
1920 types |= LogEntry::TYPE_GENERAL;
1922 if (_log_warning->GetValue ()) {
1923 types |= LogEntry::TYPE_WARNING;
1925 if (_log_error->GetValue ()) {
1926 types |= LogEntry::TYPE_ERROR;
1928 if (_log_timing->GetValue ()) {
1929 types |= LogEntry::TYPE_TIMING;
1931 if (_log_debug_threed->GetValue ()) {
1932 types |= LogEntry::TYPE_DEBUG_THREE_D;
1934 if (_log_debug_encode->GetValue ()) {
1935 types |= LogEntry::TYPE_DEBUG_ENCODE;
1937 if (_log_debug_email->GetValue ()) {
1938 types |= LogEntry::TYPE_DEBUG_EMAIL;
1940 if (_log_debug_video_view->GetValue()) {
1941 types |= LogEntry::TYPE_DEBUG_VIDEO_VIEW;
1943 if (_log_debug_player->GetValue()) {
1944 types |= LogEntry::TYPE_DEBUG_PLAYER;
1946 if (_log_debug_audio_analysis->GetValue()) {
1947 types |= LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS;
1949 Config::instance()->set_log_types (types);
1952 #ifdef DCPOMATIC_WINDOWS
1953 void win32_console_changed ()
1955 Config::instance()->set_win32_console(_win32_console->GetValue());
1959 wxChoice* _video_display_mode = nullptr;
1960 wxSpinCtrl* _frames_in_memory_multiplier = nullptr;
1961 CheckBox* _show_experimental_audio_processors = nullptr;
1962 CheckBox* _only_servers_encode = nullptr;
1963 NameFormatEditor* _dcp_metadata_filename_format = nullptr;
1964 NameFormatEditor* _dcp_asset_filename_format = nullptr;
1965 CheckBox* _log_general = nullptr;
1966 CheckBox* _log_warning = nullptr;
1967 CheckBox* _log_error = nullptr;
1968 CheckBox* _log_timing = nullptr;
1969 CheckBox* _log_debug_threed = nullptr;
1970 CheckBox* _log_debug_encode = nullptr;
1971 CheckBox* _log_debug_email = nullptr;
1972 CheckBox* _log_debug_video_view = nullptr;
1973 CheckBox* _log_debug_player = nullptr;
1974 CheckBox* _log_debug_audio_analysis = nullptr;
1975 #ifdef DCPOMATIC_WINDOWS
1976 CheckBox* _win32_console = nullptr;
1981 wxPreferencesEditor*
1982 create_full_config_dialog ()
1984 auto e = new wxPreferencesEditor ();
1986 #ifdef DCPOMATIC_OSX
1987 /* Width that we force some of the config panels to be on OSX so that
1988 the containing window doesn't shrink too much when we select those panels.
1989 This is obviously an unpleasant hack.
1991 wxSize ps = wxSize(900, -1);
1992 int const border = 16;
1994 wxSize ps = wxSize (-1, -1);
1995 int const border = 8;
1998 e->AddPage (new FullGeneralPage (ps, border));
1999 e->AddPage (new SoundPage (ps, border));
2000 e->AddPage (new DefaultsPage (ps, border));
2001 e->AddPage (new EncodingServersPage(ps, border));
2002 #ifdef DCPOMATIC_GROK
2003 e->AddPage (new GPUPage (ps, border));
2005 e->AddPage (new KeysPage (ps, border));
2006 e->AddPage (new TMSPage (ps, border));
2007 e->AddPage (new EmailPage (ps, border));
2008 e->AddPage (new KDMEmailPage (ps, border));
2009 e->AddPage (new NotificationsPage (ps, border));
2010 e->AddPage (new CoverSheetPage (ps, border));
2011 e->AddPage (new IdentifiersPage (ps, border));
2012 e->AddPage (new NonStandardPage (ps, border));
2013 e->AddPage (new AdvancedPage (ps, border));