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 "dir_picker_ctrl.h"
32 #include "editable_list.h"
33 #include "email_dialog.h"
34 #include "file_picker_ctrl.h"
35 #include "filter_dialog.h"
36 #include "full_config_dialog.h"
37 #include "kdm_choice.h"
38 #include "make_chain_dialog.h"
39 #include "nag_dialog.h"
40 #include "name_format_editor.h"
41 #include "password_entry.h"
42 #include "send_test_email_dialog.h"
43 #include "server_dialog.h"
44 #include "static_text.h"
46 #include "lib/config.h"
47 #include "lib/cross.h"
48 #include "lib/dcp_content_type.h"
49 #include "lib/emailer.h"
50 #include "lib/exceptions.h"
51 #include "lib/filter.h"
53 #include "lib/ratio.h"
55 #include <dcp/certificate_chain.h>
56 #include <dcp/exceptions.h>
57 #include <dcp/locale_convert.h>
58 #include <dcp/warnings.h>
59 LIBDCP_DISABLE_WARNINGS
60 #include <wx/filepicker.h>
61 #include <wx/preferences.h>
62 #include <wx/spinctrl.h>
63 #include <wx/stdpaths.h>
64 LIBDCP_ENABLE_WARNINGS
66 #include <boost/filesystem.hpp>
76 using std::shared_ptr;
80 using boost::optional;
81 #if BOOST_VERSION >= 106100
82 using namespace boost::placeholders;
84 using dcp::locale_convert;
90 icon_path(string name)
92 return gui_is_dark() ? bitmap_path(String::compose("%1_white.png", name)) : bitmap_path(String::compose("%1_black.png", name));
97 class FullGeneralPage : public GeneralPage
100 FullGeneralPage (wxSize panel_size, int border)
101 : GeneralPage (panel_size, border)
105 void setup () override
107 auto table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
108 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
111 add_language_controls (table, r);
113 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic should use"), true, wxGBPosition (r, 0));
114 _master_encoding_threads = new wxSpinCtrl (_panel);
115 table->Add (_master_encoding_threads, wxGBPosition (r, 1));
118 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic encode server should use"), true, wxGBPosition (r, 0));
119 _server_encoding_threads = new wxSpinCtrl (_panel);
120 table->Add (_server_encoding_threads, wxGBPosition (r, 1));
123 add_label_to_sizer (table, _panel, _("Configuration file"), true, wxGBPosition (r, 0));
124 _config_file = new FilePickerCtrl (_panel, _("Select configuration file"), "*.xml", true, false);
125 table->Add (_config_file, wxGBPosition (r, 1));
128 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
129 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml", true, false);
130 table->Add (_cinemas_file, wxGBPosition (r, 1));
131 auto export_cinemas = new Button (_panel, _("Export..."));
132 table->Add (export_cinemas, wxGBPosition (r, 2));
135 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
136 _analyse_ebur128 = new CheckBox (_panel, _("Find integrated loudness, true peak and loudness range when analysing audio"));
137 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
141 _automatic_audio_analysis = new CheckBox (_panel, _("Automatically analyse content audio"));
142 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
145 add_update_controls (table, r);
147 _config_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::config_file_changed, this));
148 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::cinemas_file_changed, this));
150 _master_encoding_threads->SetRange (1, 128);
151 _master_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::master_encoding_threads_changed, this));
152 _server_encoding_threads->SetRange (1, 128);
153 _server_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::server_encoding_threads_changed, this));
154 export_cinemas->Bind (wxEVT_BUTTON, boost::bind (&FullGeneralPage::export_cinemas_file, this));
156 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
157 _analyse_ebur128->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::analyse_ebur128_changed, this));
159 _automatic_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::automatic_audio_analysis_changed, this));
162 void config_changed () override
164 auto config = Config::instance ();
166 checked_set (_master_encoding_threads, config->master_encoding_threads ());
167 checked_set (_server_encoding_threads, config->server_encoding_threads ());
168 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
169 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
171 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
172 checked_set (_config_file, config->config_read_file());
173 checked_set (_cinemas_file, config->cinemas_file());
175 GeneralPage::config_changed ();
178 void export_cinemas_file ()
180 auto d = new wxFileDialog (
181 _panel, _("Select Cinemas File"), wxEmptyString, wxEmptyString, wxT("XML files (*.xml)|*.xml"),
182 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
185 if (d->ShowModal () == wxID_OK) {
186 boost::filesystem::copy_file(Config::instance()->cinemas_file(), wx_to_std(d->GetPath()), boost::filesystem::copy_option::overwrite_if_exists);
191 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
192 void analyse_ebur128_changed ()
194 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue());
198 void automatic_audio_analysis_changed ()
200 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue());
203 void master_encoding_threads_changed ()
205 Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue());
208 void server_encoding_threads_changed ()
210 Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue());
213 void config_file_changed ()
215 auto config = Config::instance();
216 boost::filesystem::path new_file = wx_to_std(_config_file->GetPath());
217 if (new_file == config->config_read_file()) {
220 bool copy_and_link = true;
221 if (boost::filesystem::exists(new_file)) {
222 auto d = new ConfigMoveDialog (_panel, new_file);
223 if (d->ShowModal() == wxID_OK) {
224 copy_and_link = false;
231 if (new_file != config->config_read_file()) {
232 config->copy_and_link (new_file);
235 config->link (new_file);
239 void cinemas_file_changed ()
241 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
244 wxSpinCtrl* _master_encoding_threads;
245 wxSpinCtrl* _server_encoding_threads;
246 FilePickerCtrl* _config_file;
247 FilePickerCtrl* _cinemas_file;
248 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
249 wxCheckBox* _analyse_ebur128;
251 wxCheckBox* _automatic_audio_analysis;
255 class DefaultsPage : public Page
258 DefaultsPage (wxSize panel_size, int border)
259 : Page (panel_size, border)
262 wxString GetName () const override
264 return _("Defaults");
268 wxBitmap GetLargeIcon () const override
270 return wxBitmap(icon_path("defaults"), wxBITMAP_TYPE_PNG);
275 void setup () override
277 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
278 table->AddGrowableCol (1, 1);
279 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
282 add_label_to_sizer (table, _panel, _("Default duration of still images"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
283 auto s = new wxBoxSizer (wxHORIZONTAL);
284 _still_length = new wxSpinCtrl (_panel);
285 s->Add (_still_length);
286 add_label_to_sizer (s, _panel, _("s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
290 add_label_to_sizer (table, _panel, _("Default directory for new films"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
291 #ifdef DCPOMATIC_USE_OWN_PICKER
292 _directory = new DirPickerCtrl (_panel);
294 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
296 table->Add (_directory, 1, wxEXPAND);
298 add_label_to_sizer (table, _panel, _("Default container"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
299 _container = new wxChoice (_panel, wxID_ANY);
300 table->Add (_container);
302 add_label_to_sizer (table, _panel, _("Default content type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
303 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
304 table->Add (_dcp_content_type);
306 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
307 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
308 table->Add (_dcp_audio_channels);
311 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
312 auto s = new wxBoxSizer (wxHORIZONTAL);
313 _j2k_bandwidth = new wxSpinCtrl (_panel);
314 s->Add (_j2k_bandwidth);
315 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
320 add_label_to_sizer (table, _panel, _("Default audio delay"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
321 auto s = new wxBoxSizer (wxHORIZONTAL);
322 _audio_delay = new wxSpinCtrl (_panel);
323 s->Add (_audio_delay);
324 add_label_to_sizer (s, _panel, _("ms"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
328 add_label_to_sizer (table, _panel, _("Default standard"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
329 _standard = new wxChoice (_panel, wxID_ANY);
330 table->Add (_standard);
332 table->Add (_enable_metadata["facility"] = new CheckBox (_panel, _("Default facility")), 0, wxALIGN_CENTRE_VERTICAL);
333 table->Add (_metadata["facility"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
335 table->Add (_enable_metadata["studio"] = new CheckBox (_panel, _("Default studio")), 0, wxALIGN_CENTRE_VERTICAL);
336 table->Add (_metadata["studio"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
338 table->Add (_enable_metadata["chain"] = new CheckBox (_panel, _("Default chain")), 0, wxALIGN_CENTRE_VERTICAL);
339 table->Add (_metadata["chain"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
341 table->Add (_enable_metadata["distributor"] = new CheckBox (_panel, _("Default distributor")), 0, wxALIGN_CENTRE_VERTICAL);
342 table->Add (_metadata["distributor"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
344 add_label_to_sizer (table, _panel, _("Default KDM directory"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
345 #ifdef DCPOMATIC_USE_OWN_PICKER
346 _kdm_directory = new DirPickerCtrl (_panel);
348 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
350 table->Add (_kdm_directory, 1, wxEXPAND);
352 add_label_to_sizer (table, _panel, _("Default KDM type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
353 _kdm_type = new KDMChoice (_panel);
354 table->Add (_kdm_type, 1, wxEXPAND);
356 add_label_to_sizer (table, _panel, _("Default KDM duration"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
357 _kdm_duration = new wxSpinCtrl (_panel);
358 _kdm_duration_unit = new wxChoice (_panel, wxID_ANY);
359 auto kdm_duration_sizer = new wxBoxSizer (wxHORIZONTAL);
360 kdm_duration_sizer->Add (_kdm_duration, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
361 kdm_duration_sizer->Add (_kdm_duration_unit, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
362 table->Add (kdm_duration_sizer, 1, wxEXPAND);
364 table->Add (_use_isdcf_name_by_default = new CheckBox(_panel, _("Use ISDCF name by default")), 0, wxALIGN_CENTRE_VERTICAL);
366 _still_length->SetRange (1, 3600);
367 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
369 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
370 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
371 _kdm_type->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_type_changed, this));
372 _kdm_duration_unit->Append (_("days"));
373 _kdm_duration_unit->Append (_("weeks"));
374 _kdm_duration_unit->Append (_("months"));
375 _kdm_duration_unit->Append (_("years"));
377 _kdm_duration->Bind (wxEVT_SPINCTRL, boost::bind(&DefaultsPage::kdm_duration_changed, this));
378 _kdm_duration_unit->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_duration_changed, this));
380 _use_isdcf_name_by_default->Bind (wxEVT_CHECKBOX, boost::bind(&DefaultsPage::use_isdcf_name_by_default_changed, this));
382 for (auto i: Ratio::containers()) {
383 _container->Append (std_to_wx(i->container_nickname()));
386 _container->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::container_changed, this));
388 for (auto i: DCPContentType::all()) {
389 _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
392 setup_audio_channels_choice (_dcp_audio_channels, 2);
394 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
395 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
397 _j2k_bandwidth->SetRange (50, 250);
398 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
400 _audio_delay->SetRange (-1000, 1000);
401 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
403 _standard->Append (_("SMPTE"));
404 _standard->Append (_("Interop"));
405 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
407 for (auto const& i: _enable_metadata) {
408 i.second->Bind (wxEVT_CHECKBOX, boost::bind(&DefaultsPage::metadata_changed, this));
411 for (auto const& i: _metadata) {
412 i.second->Bind (wxEVT_TEXT, boost::bind(&DefaultsPage::metadata_changed, this));
416 void config_changed () override
418 auto config = Config::instance ();
420 auto containers = Ratio::containers ();
421 for (size_t i = 0; i < containers.size(); ++i) {
422 if (containers[i] == config->default_container()) {
423 _container->SetSelection (i);
427 auto const ct = DCPContentType::all ();
428 for (size_t i = 0; i < ct.size(); ++i) {
429 if (ct[i] == config->default_dcp_content_type()) {
430 _dcp_content_type->SetSelection (i);
434 checked_set (_still_length, config->default_still_length ());
435 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
436 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
437 _kdm_type->set (config->default_kdm_type());
438 checked_set (_use_isdcf_name_by_default, config->use_isdcf_name_by_default());
439 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
440 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
441 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
442 checked_set (_audio_delay, config->default_audio_delay ());
443 checked_set (_standard, config->default_interop() ? 1 : 0);
445 auto metadata = config->default_metadata();
447 for (auto const& i: metadata) {
448 _enable_metadata[i.first]->SetValue(true);
449 checked_set (_metadata[i.first], i.second);
452 for (auto const& i: _enable_metadata) {
453 if (metadata.find(i.first) == metadata.end()) {
454 checked_set (i.second, false);
458 for (auto const& i: _metadata) {
459 if (metadata.find(i.first) == metadata.end()) {
460 checked_set (i.second, wxT(""));
464 checked_set (_kdm_duration, config->default_kdm_duration().duration);
465 switch (config->default_kdm_duration().unit) {
466 case RoughDuration::Unit::DAYS:
467 _kdm_duration->SetRange(1, 365);
468 checked_set (_kdm_duration_unit, 0);
470 case RoughDuration::Unit::WEEKS:
471 _kdm_duration->SetRange(1, 52);
472 checked_set (_kdm_duration_unit, 1);
474 case RoughDuration::Unit::MONTHS:
475 _kdm_duration->SetRange(1, 12);
476 checked_set (_kdm_duration_unit, 2);
478 case RoughDuration::Unit::YEARS:
479 _kdm_duration->SetRange(1, 40);
480 checked_set (_kdm_duration_unit, 3);
484 setup_sensitivity ();
487 void kdm_duration_changed ()
489 auto config = Config::instance();
490 auto duration = _kdm_duration->GetValue();
491 RoughDuration::Unit unit = RoughDuration::Unit::DAYS;
492 switch (_kdm_duration_unit->GetSelection()) {
494 unit = RoughDuration::Unit::DAYS;
497 unit = RoughDuration::Unit::WEEKS;
500 unit = RoughDuration::Unit::MONTHS;
503 unit = RoughDuration::Unit::YEARS;
506 config->set_default_kdm_duration (RoughDuration(duration, unit));
509 void j2k_bandwidth_changed ()
511 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
514 void audio_delay_changed ()
516 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
519 void dcp_audio_channels_changed ()
521 int const s = _dcp_audio_channels->GetSelection ();
522 if (s != wxNOT_FOUND) {
523 Config::instance()->set_default_dcp_audio_channels (
524 locale_convert<int>(string_client_data(_dcp_audio_channels->GetClientObject(s)))
529 void directory_changed ()
531 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
534 void kdm_directory_changed ()
536 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
539 void kdm_type_changed ()
541 Config::instance()->set_default_kdm_type(_kdm_type->get());
544 void use_isdcf_name_by_default_changed ()
546 Config::instance()->set_use_isdcf_name_by_default (_use_isdcf_name_by_default->GetValue());
549 void still_length_changed ()
551 Config::instance()->set_default_still_length (_still_length->GetValue ());
554 void container_changed ()
556 auto ratio = Ratio::containers ();
557 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
560 void dcp_content_type_changed ()
562 auto ct = DCPContentType::all ();
563 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
566 void standard_changed ()
568 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
571 void metadata_changed ()
573 map<string, string> metadata;
574 for (auto const& i: _enable_metadata) {
575 if (i.second->GetValue()) {
576 metadata[i.first] = wx_to_std(_metadata[i.first]->GetValue());
579 Config::instance()->set_default_metadata (metadata);
580 setup_sensitivity ();
583 void setup_sensitivity ()
585 for (auto const& i: _enable_metadata) {
586 _metadata[i.first]->Enable(i.second->GetValue());
590 wxSpinCtrl* _j2k_bandwidth;
591 wxSpinCtrl* _audio_delay;
592 wxSpinCtrl* _still_length;
593 #ifdef DCPOMATIC_USE_OWN_PICKER
594 DirPickerCtrl* _directory;
595 DirPickerCtrl* _kdm_directory;
597 wxDirPickerCtrl* _directory;
598 wxDirPickerCtrl* _kdm_directory;
600 KDMChoice* _kdm_type;
601 wxSpinCtrl* _kdm_duration;
602 wxChoice* _kdm_duration_unit;
603 wxCheckBox* _use_isdcf_name_by_default;
604 wxChoice* _container;
605 wxChoice* _dcp_content_type;
606 wxChoice* _dcp_audio_channels;
608 map<string, CheckBox*> _enable_metadata;
609 map<string, wxTextCtrl*> _metadata;
613 class EncodingServersPage : public Page
616 EncodingServersPage (wxSize panel_size, int border)
617 : Page (panel_size, border)
620 wxString GetName () const override
626 wxBitmap GetLargeIcon () const override
628 return wxBitmap(icon_path("servers"), wxBITMAP_TYPE_PNG);
633 void setup () override
635 _use_any_servers = new CheckBox (_panel, _("Search network for servers"));
636 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
638 vector<EditableListColumn> columns;
639 columns.push_back (EditableListColumn(_("IP address / host name")));
640 _servers_list = new EditableList<string, ServerDialog> (
643 boost::bind (&Config::servers, Config::instance()),
644 boost::bind (&Config::set_servers, Config::instance(), _1),
645 boost::bind (&EncodingServersPage::server_column, this, _1),
646 EditableListTitle::INVISIBLE,
647 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
650 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
652 _use_any_servers->Bind (wxEVT_CHECKBOX, boost::bind(&EncodingServersPage::use_any_servers_changed, this));
655 void config_changed () override
657 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
658 _servers_list->refresh ();
661 void use_any_servers_changed ()
663 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
666 string server_column (string s)
671 wxCheckBox* _use_any_servers;
672 EditableList<string, ServerDialog>* _servers_list;
676 class TMSPage : public Page
679 TMSPage (wxSize panel_size, int border)
680 : Page (panel_size, border)
683 wxString GetName () const override
689 wxBitmap GetLargeIcon () const override
691 return wxBitmap(icon_path("tms"), wxBITMAP_TYPE_PNG);
696 void setup () override
698 _upload = new CheckBox (_panel, _("Upload DCP to TMS after creation"));
699 _panel->GetSizer()->Add (_upload, 0, wxALL | wxEXPAND, _border);
701 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
702 table->AddGrowableCol (1, 1);
703 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
705 add_label_to_sizer (table, _panel, _("Protocol"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
706 _tms_protocol = new wxChoice (_panel, wxID_ANY);
707 table->Add (_tms_protocol, 1, wxEXPAND);
709 add_label_to_sizer (table, _panel, _("IP address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
710 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
711 table->Add (_tms_ip, 1, wxEXPAND);
713 add_label_to_sizer (table, _panel, _("Target path"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
714 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
715 table->Add (_tms_path, 1, wxEXPAND);
717 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
718 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
719 table->Add (_tms_user, 1, wxEXPAND);
721 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
722 _tms_password = new PasswordEntry (_panel);
723 table->Add (_tms_password->get_panel(), 1, wxEXPAND);
725 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
726 _tms_protocol->Append (_("FTP (for Dolby)"));
728 _upload->Bind (wxEVT_CHECKBOX, boost::bind(&TMSPage::upload_changed, this));
729 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
730 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
731 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
732 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
733 _tms_password->Changed.connect (boost::bind (&TMSPage::tms_password_changed, this));
736 void config_changed () override
738 auto config = Config::instance ();
740 checked_set (_upload, config->upload_after_make_dcp());
741 checked_set (_tms_protocol, static_cast<int>(config->tms_protocol()));
742 checked_set (_tms_ip, config->tms_ip ());
743 checked_set (_tms_path, config->tms_path ());
744 checked_set (_tms_user, config->tms_user ());
745 checked_set (_tms_password, config->tms_password ());
748 void upload_changed ()
750 Config::instance()->set_upload_after_make_dcp (_upload->GetValue());
753 void tms_protocol_changed ()
755 Config::instance()->set_tms_protocol(static_cast<FileTransferProtocol>(_tms_protocol->GetSelection()));
758 void tms_ip_changed ()
760 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
763 void tms_path_changed ()
765 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
768 void tms_user_changed ()
770 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
773 void tms_password_changed ()
775 Config::instance()->set_tms_password (_tms_password->get());
779 wxChoice* _tms_protocol;
781 wxTextCtrl* _tms_path;
782 wxTextCtrl* _tms_user;
783 PasswordEntry* _tms_password;
787 class EmailPage : public Page
790 EmailPage (wxSize panel_size, int border)
791 : Page (panel_size, border)
794 wxString GetName () const override
800 wxBitmap GetLargeIcon () const override
802 return wxBitmap(icon_path("email"), wxBITMAP_TYPE_PNG);
807 void setup () override
809 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
810 table->AddGrowableCol (1, 1);
811 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
813 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
815 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
816 _server = new wxTextCtrl (_panel, wxID_ANY);
817 s->Add (_server, 1, wxEXPAND | wxALL);
818 add_label_to_sizer (s, _panel, _("port"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
819 _port = new wxSpinCtrl (_panel, wxID_ANY);
820 _port->SetRange (0, 65535);
822 add_label_to_sizer (s, _panel, _("protocol"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
823 _protocol = new wxChoice (_panel, wxID_ANY);
824 /* Make sure this matches the switches in config_changed and port_changed below */
825 _protocol->Append (_("Auto"));
826 _protocol->Append (_("Plain"));
827 _protocol->Append (_("STARTTLS"));
828 _protocol->Append (_("SSL"));
829 s->Add (_protocol, 1, wxALIGN_CENTER_VERTICAL);
830 table->Add (s, 1, wxEXPAND | wxALL);
833 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
834 _user = new wxTextCtrl (_panel, wxID_ANY);
835 table->Add (_user, 1, wxEXPAND | wxALL);
837 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
838 _password = new PasswordEntry (_panel);
839 table->Add (_password->get_panel(), 1, wxEXPAND | wxALL);
841 table->AddSpacer (0);
842 _send_test_email = new Button (_panel, _("Send test email..."));
843 table->Add (_send_test_email);
845 _server->Bind (wxEVT_TEXT, boost::bind(&EmailPage::server_changed, this));
846 _port->Bind (wxEVT_SPINCTRL, boost::bind(&EmailPage::port_changed, this));
847 _protocol->Bind (wxEVT_CHOICE, boost::bind(&EmailPage::protocol_changed, this));
848 _user->Bind (wxEVT_TEXT, boost::bind(&EmailPage::user_changed, this));
849 _password->Changed.connect (boost::bind(&EmailPage::password_changed, this));
850 _send_test_email->Bind (wxEVT_BUTTON, boost::bind(&EmailPage::send_test_email_clicked, this));
853 void config_changed () override
855 auto config = Config::instance ();
857 checked_set (_server, config->mail_server());
858 checked_set (_port, config->mail_port());
859 switch (config->mail_protocol()) {
860 case EmailProtocol::AUTO:
861 checked_set (_protocol, 0);
863 case EmailProtocol::PLAIN:
864 checked_set (_protocol, 1);
866 case EmailProtocol::STARTTLS:
867 checked_set (_protocol, 2);
869 case EmailProtocol::SSL:
870 checked_set (_protocol, 3);
873 checked_set (_user, config->mail_user());
874 checked_set (_password, config->mail_password());
877 void server_changed ()
879 Config::instance()->set_mail_server(wx_to_std(_server->GetValue()));
884 Config::instance()->set_mail_port(_port->GetValue());
887 void protocol_changed ()
889 switch (_protocol->GetSelection()) {
891 Config::instance()->set_mail_protocol(EmailProtocol::AUTO);
894 Config::instance()->set_mail_protocol(EmailProtocol::PLAIN);
897 Config::instance()->set_mail_protocol(EmailProtocol::STARTTLS);
900 Config::instance()->set_mail_protocol(EmailProtocol::SSL);
907 Config::instance()->set_mail_user (wx_to_std (_user->GetValue ()));
910 void password_changed ()
912 Config::instance()->set_mail_password(_password->get());
915 void send_test_email_clicked ()
917 auto dialog = new SendTestEmailDialog(_panel);
918 auto result = dialog->ShowModal();
920 if (result == wxID_OK) {
922 wx_to_std(dialog->from()),
923 { wx_to_std(dialog->to()) },
924 wx_to_std(_("DCP-o-matic test email")),
925 wx_to_std(_("This is a test email from DCP-o-matic."))
927 auto config = Config::instance();
929 emailer.send (config->mail_server(), config->mail_port(), config->mail_protocol(), config->mail_user(), config->mail_password());
930 } catch (NetworkError& e) {
931 error_dialog (_panel, std_to_wx(e.summary()), std_to_wx(e.detail().get_value_or("")));
933 } catch (std::exception& e) {
934 error_dialog (_panel, _("Test email sending failed."), std_to_wx(e.what()));
937 error_dialog (_panel, _("Test email sending failed."));
940 message_dialog (_panel, _("Test email sent."));
948 PasswordEntry* _password;
949 Button* _send_test_email;
953 class KDMEmailPage : public Page
957 KDMEmailPage (wxSize panel_size, int border)
959 /* We have to force both width and height of this one */
960 : Page (wxSize (panel_size.GetWidth(), 128), border)
962 : Page (panel_size, border)
966 wxString GetName () const override
968 return _("KDM Email");
972 wxBitmap GetLargeIcon () const override
974 return wxBitmap(icon_path("kdm_email"), wxBITMAP_TYPE_PNG);
979 void setup () override
981 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
982 table->AddGrowableCol (1, 1);
983 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
985 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
986 _subject = new wxTextCtrl (_panel, wxID_ANY);
987 table->Add (_subject, 1, wxEXPAND | wxALL);
989 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
990 _from = new wxTextCtrl (_panel, wxID_ANY);
991 table->Add (_from, 1, wxEXPAND | wxALL);
993 vector<EditableListColumn> columns;
994 columns.push_back (EditableListColumn(_("Address")));
995 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
996 _cc = new EditableList<string, EmailDialog> (
999 bind (&Config::kdm_cc, Config::instance()),
1000 bind (&Config::set_kdm_cc, Config::instance(), _1),
1001 [] (string s, int) {
1004 EditableListTitle::VISIBLE,
1005 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
1007 table->Add (_cc, 1, wxEXPAND | wxALL);
1009 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1010 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1011 table->Add (_bcc, 1, wxEXPAND | wxALL);
1013 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1014 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1016 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1017 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1021 _subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1022 _from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1023 _bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1024 _email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1025 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_email, this));
1028 void config_changed () override
1030 auto config = Config::instance ();
1032 checked_set (_subject, config->kdm_subject ());
1033 checked_set (_from, config->kdm_from ());
1034 checked_set (_bcc, config->kdm_bcc ());
1035 checked_set (_email, Config::instance()->kdm_email ());
1038 void kdm_subject_changed ()
1040 Config::instance()->set_kdm_subject (wx_to_std (_subject->GetValue ()));
1043 void kdm_from_changed ()
1045 Config::instance()->set_kdm_from (wx_to_std (_from->GetValue ()));
1048 void kdm_bcc_changed ()
1050 Config::instance()->set_kdm_bcc (wx_to_std (_bcc->GetValue ()));
1053 void kdm_email_changed ()
1055 if (_email->GetValue().IsEmpty ()) {
1056 /* Sometimes we get sent an erroneous notification that the email
1057 is empty; I don't know why.
1061 Config::instance()->set_kdm_email (wx_to_std (_email->GetValue ()));
1066 Config::instance()->reset_kdm_email ();
1067 checked_set (_email, Config::instance()->kdm_email ());
1070 wxTextCtrl* _subject;
1072 EditableList<string, EmailDialog>* _cc;
1075 wxButton* _reset_email;
1079 class NotificationsPage : public Page
1082 NotificationsPage (wxSize panel_size, int border)
1083 #ifdef DCPOMATIC_OSX
1084 /* We have to force both width and height of this one */
1085 : Page (wxSize (panel_size.GetWidth(), 128), border)
1087 : Page (panel_size, border)
1091 wxString GetName () const override
1093 return _("Notifications");
1096 #ifdef DCPOMATIC_OSX
1097 wxBitmap GetLargeIcon () const override
1099 return wxBitmap(icon_path("notifications"), wxBITMAP_TYPE_PNG);
1104 void setup () override
1106 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1107 table->AddGrowableCol (1, 1);
1108 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1110 _enable_message_box = new CheckBox (_panel, _("Message box"));
1111 table->Add (_enable_message_box, 1, wxEXPAND | wxALL);
1112 table->AddSpacer (0);
1114 _enable_email = new CheckBox (_panel, _("Email"));
1115 table->Add (_enable_email, 1, wxEXPAND | wxALL);
1116 table->AddSpacer (0);
1118 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1119 _subject = new wxTextCtrl (_panel, wxID_ANY);
1120 table->Add (_subject, 1, wxEXPAND | wxALL);
1122 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1123 _from = new wxTextCtrl (_panel, wxID_ANY);
1124 table->Add (_from, 1, wxEXPAND | wxALL);
1126 add_label_to_sizer (table, _panel, _("To address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1127 _to = new wxTextCtrl (_panel, wxID_ANY);
1128 table->Add (_to, 1, wxEXPAND | wxALL);
1130 vector<EditableListColumn> columns;
1131 columns.push_back (EditableListColumn(_("Address")));
1132 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1133 _cc = new EditableList<string, EmailDialog> (
1136 bind (&Config::notification_cc, Config::instance()),
1137 bind (&Config::set_notification_cc, Config::instance(), _1),
1138 [] (string s, int) {
1141 EditableListTitle::VISIBLE,
1142 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
1144 table->Add (_cc, 1, wxEXPAND | wxALL);
1146 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1147 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1148 table->Add (_bcc, 1, wxEXPAND | wxALL);
1150 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1151 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1153 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1154 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1158 _enable_message_box->Bind (wxEVT_CHECKBOX, boost::bind (&NotificationsPage::type_changed, this, _enable_message_box, Config::MESSAGE_BOX));
1159 _enable_email->Bind (wxEVT_CHECKBOX, boost::bind (&NotificationsPage::type_changed, this, _enable_email, Config::EMAIL));
1161 _subject->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_subject_changed, this));
1162 _from->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_from_changed, this));
1163 _to->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_to_changed, this));
1164 _bcc->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_bcc_changed, this));
1165 _email->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_email_changed, this));
1166 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&NotificationsPage::reset_email, this));
1168 setup_sensitivity ();
1171 void setup_sensitivity ()
1173 bool const s = _enable_email->GetValue();
1174 _subject->Enable(s);
1180 _reset_email->Enable(s);
1183 void config_changed () override
1185 auto config = Config::instance ();
1187 checked_set (_enable_message_box, config->notification(Config::MESSAGE_BOX));
1188 checked_set (_enable_email, config->notification(Config::EMAIL));
1189 checked_set (_subject, config->notification_subject ());
1190 checked_set (_from, config->notification_from ());
1191 checked_set (_to, config->notification_to ());
1192 checked_set (_bcc, config->notification_bcc ());
1193 checked_set (_email, Config::instance()->notification_email ());
1195 setup_sensitivity ();
1198 void notification_subject_changed ()
1200 Config::instance()->set_notification_subject(wx_to_std(_subject->GetValue()));
1203 void notification_from_changed ()
1205 Config::instance()->set_notification_from(wx_to_std(_from->GetValue()));
1208 void notification_to_changed ()
1210 Config::instance()->set_notification_to(wx_to_std(_to->GetValue()));
1213 void notification_bcc_changed ()
1215 Config::instance()->set_notification_bcc(wx_to_std(_bcc->GetValue()));
1218 void notification_email_changed ()
1220 if (_email->GetValue().IsEmpty()) {
1221 /* Sometimes we get sent an erroneous notification that the email
1222 is empty; I don't know why.
1226 Config::instance()->set_notification_email(wx_to_std(_email->GetValue()));
1231 Config::instance()->reset_notification_email();
1232 checked_set (_email, Config::instance()->notification_email());
1235 void type_changed (wxCheckBox* b, Config::Notification n)
1237 Config::instance()->set_notification(n, b->GetValue());
1238 setup_sensitivity ();
1241 wxCheckBox* _enable_message_box;
1242 wxCheckBox* _enable_email;
1244 wxTextCtrl* _subject;
1247 EditableList<string, EmailDialog>* _cc;
1250 wxButton* _reset_email;
1254 class CoverSheetPage : public Page
1258 CoverSheetPage (wxSize panel_size, int border)
1259 #ifdef DCPOMATIC_OSX
1260 /* We have to force both width and height of this one */
1261 : Page (wxSize (panel_size.GetWidth(), 128), border)
1263 : Page (panel_size, border)
1267 wxString GetName () const override
1269 return _("Cover Sheet");
1272 #ifdef DCPOMATIC_OSX
1273 wxBitmap GetLargeIcon () const override
1275 return wxBitmap(icon_path("cover_sheet"), wxBITMAP_TYPE_PNG);
1280 void setup () override
1282 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1283 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
1285 _reset_cover_sheet = new Button (_panel, _("Reset to default text"));
1286 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
1288 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
1289 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
1292 void config_changed () override
1294 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1297 void cover_sheet_changed ()
1299 if (_cover_sheet->GetValue().IsEmpty ()) {
1300 /* Sometimes we get sent an erroneous notification that the cover sheet
1301 is empty; I don't know why.
1305 Config::instance()->set_cover_sheet(wx_to_std(_cover_sheet->GetValue()));
1308 void reset_cover_sheet ()
1310 Config::instance()->reset_cover_sheet();
1311 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1314 wxTextCtrl* _cover_sheet;
1315 wxButton* _reset_cover_sheet;
1319 class IdentifiersPage : public Page
1322 IdentifiersPage (wxSize panel_size, int border)
1323 : Page (panel_size, border)
1326 wxString GetName () const override
1328 return _("Identifiers");
1331 #ifdef DCPOMATIC_OSX
1332 wxBitmap GetLargeIcon () const override
1334 return wxBitmap(icon_path("identifiers"), wxBITMAP_TYPE_PNG);
1339 void setup () override
1341 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1342 table->AddGrowableCol (1, 1);
1344 add_label_to_sizer (table, _panel, _("Issuer"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1345 _issuer = new wxTextCtrl (_panel, wxID_ANY);
1346 _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."));
1347 table->Add (_issuer, 1, wxALL | wxEXPAND);
1349 add_label_to_sizer (table, _panel, _("Creator"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1350 _creator = new wxTextCtrl (_panel, wxID_ANY);
1351 _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."));
1352 table->Add (_creator, 1, wxALL | wxEXPAND);
1354 add_label_to_sizer (table, _panel, _("Company name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1355 _company_name = new wxTextCtrl (_panel, wxID_ANY);
1356 _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."));
1357 table->Add (_company_name, 1, wxALL | wxEXPAND);
1359 add_label_to_sizer (table, _panel, _("Product name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1360 _product_name = new wxTextCtrl (_panel, wxID_ANY);
1361 _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."));
1362 table->Add (_product_name, 1, wxALL | wxEXPAND);
1364 add_label_to_sizer (table, _panel, _("Product version"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1365 _product_version = new wxTextCtrl (_panel, wxID_ANY);
1366 _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."));
1367 table->Add (_product_version, 1, wxALL | wxEXPAND);
1369 add_label_to_sizer (table, _panel, _("JPEG2000 comment"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1370 _j2k_comment = new wxTextCtrl (_panel, wxID_ANY);
1371 _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."));
1372 table->Add (_j2k_comment, 1, wxALL | wxEXPAND);
1374 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1376 _issuer->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::issuer_changed, this));
1377 _creator->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::creator_changed, this));
1378 _company_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::company_name_changed, this));
1379 _product_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_name_changed, this));
1380 _product_version->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_version_changed, this));
1381 _j2k_comment->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::j2k_comment_changed, this));
1384 void config_changed () override
1386 auto config = Config::instance ();
1387 checked_set (_issuer, config->dcp_issuer ());
1388 checked_set (_creator, config->dcp_creator ());
1389 checked_set (_company_name, config->dcp_company_name ());
1390 checked_set (_product_name, config->dcp_product_name ());
1391 checked_set (_product_version, config->dcp_product_version ());
1392 checked_set (_j2k_comment, config->dcp_j2k_comment ());
1395 void issuer_changed ()
1397 Config::instance()->set_dcp_issuer(wx_to_std(_issuer->GetValue()));
1400 void creator_changed ()
1402 Config::instance()->set_dcp_creator(wx_to_std(_creator->GetValue()));
1405 void company_name_changed ()
1407 Config::instance()->set_dcp_company_name(wx_to_std(_company_name->GetValue()));
1410 void product_name_changed ()
1412 Config::instance()->set_dcp_product_name(wx_to_std(_product_name->GetValue()));
1415 void product_version_changed ()
1417 Config::instance()->set_dcp_product_version(wx_to_std(_product_version->GetValue()));
1420 void j2k_comment_changed ()
1422 Config::instance()->set_dcp_j2k_comment (wx_to_std(_j2k_comment->GetValue()));
1425 wxTextCtrl* _issuer;
1426 wxTextCtrl* _creator;
1427 wxTextCtrl* _company_name;
1428 wxTextCtrl* _product_name;
1429 wxTextCtrl* _product_version;
1430 wxTextCtrl* _j2k_comment;
1434 /** @class AdvancedPage
1435 * @brief Advanced page of the preferences dialog.
1437 class AdvancedPage : public Page
1440 AdvancedPage (wxSize panel_size, int border)
1441 : Page (panel_size, border)
1444 wxString GetName () const override
1446 return _("Advanced");
1449 #ifdef DCPOMATIC_OSX
1450 wxBitmap GetLargeIcon () const override
1452 return wxBitmap(icon_path("advanced"), wxBITMAP_TYPE_PNG);
1457 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1459 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1461 flags |= wxALIGN_RIGHT;
1464 wxStaticText* m = new StaticText (parent, text);
1465 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1468 void setup () override
1470 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1471 table->AddGrowableCol (1, 1);
1472 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1475 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1476 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1477 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1478 s->Add (_maximum_j2k_bandwidth, 1);
1479 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxALIGN_CENTRE_VERTICAL);
1483 add_label_to_sizer (table, _panel, _("Video display mode"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1484 _video_display_mode = new wxChoice (_panel, wxID_ANY);
1485 table->Add (_video_display_mode);
1487 auto restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to change display mode)"), false);
1488 auto font = restart->GetFont();
1489 font.SetStyle (wxFONTSTYLE_ITALIC);
1490 font.SetPointSize (font.GetPointSize() - 1);
1491 restart->SetFont (font);
1492 table->AddSpacer (0);
1494 _allow_any_dcp_frame_rate = new CheckBox (_panel, _("Allow any DCP frame rate"));
1495 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1496 table->AddSpacer (0);
1498 _allow_any_container = new CheckBox (_panel, _("Allow full-frame and non-standard container ratios"));
1499 table->Add (_allow_any_container, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1500 restart = new StaticText (_panel, _("(restart DCP-o-matic to see all ratios)"));
1501 table->Add (restart, 1, wxEXPAND | wxALL | wxALIGN_CENTRE_VERTICAL);
1502 restart->SetFont (font);
1504 _allow_96khz_audio = new CheckBox (_panel, _("Allow creation of DCPs with 96kHz audio"));
1505 table->Add (_allow_96khz_audio, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1506 table->AddSpacer (0);
1508 _use_all_audio_channels = new CheckBox(_panel, _("Allow mapping to all audio channels"));
1509 table->Add(_use_all_audio_channels, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1510 table->AddSpacer(0);
1512 _show_experimental_audio_processors = new CheckBox (_panel, _("Show experimental audio processors"));
1513 table->Add (_show_experimental_audio_processors, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1514 table->AddSpacer (0);
1516 _only_servers_encode = new CheckBox (_panel, _("Only servers encode"));
1517 table->Add (_only_servers_encode, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1518 table->AddSpacer (0);
1521 add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1522 auto s = new wxBoxSizer (wxHORIZONTAL);
1523 _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
1524 s->Add (_frames_in_memory_multiplier, 1);
1529 auto format = create_label (_panel, _("DCP metadata filename format"), true);
1530 #ifdef DCPOMATIC_OSX
1531 auto align = new wxBoxSizer (wxHORIZONTAL);
1532 align->Add (format, 0, wxTOP, 2);
1533 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1535 table->Add (format, 0, wxTOP | wxLEFT | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1537 dcp::NameFormat::Map titles;
1538 titles['t'] = wx_to_std (_("type (cpl/pkl)"));
1539 dcp::NameFormat::Map examples;
1540 examples['t'] = "cpl";
1541 _dcp_metadata_filename_format = new NameFormatEditor (
1542 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1544 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1548 auto format = create_label (_panel, _("DCP asset filename format"), true);
1549 #ifdef DCPOMATIC_OSX
1550 auto align = new wxBoxSizer (wxHORIZONTAL);
1551 align->Add (format, 0, wxTOP, 2);
1552 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1554 table->Add (format, 0, wxTOP | wxLEFT | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1556 dcp::NameFormat::Map titles;
1557 titles['t'] = wx_to_std (_("type (j2c/pcm/sub)"));
1558 titles['r'] = wx_to_std (_("reel number"));
1559 titles['n'] = wx_to_std (_("number of reels"));
1560 titles['c'] = wx_to_std (_("content filename"));
1561 dcp::NameFormat::Map examples;
1562 examples['t'] = "j2c";
1563 examples['r'] = "1";
1564 examples['n'] = "4";
1565 examples['c'] = "myfile.mp4";
1566 _dcp_asset_filename_format = new NameFormatEditor (
1567 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1569 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1573 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1574 auto t = new wxFlexGridSizer (2);
1575 _log_general = new CheckBox (_panel, _("General"));
1576 t->Add (_log_general, 1, wxEXPAND | wxALL);
1577 _log_warning = new CheckBox (_panel, _("Warnings"));
1578 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1579 _log_error = new CheckBox (_panel, _("Errors"));
1580 t->Add (_log_error, 1, wxEXPAND | wxALL);
1581 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1582 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
1583 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1584 _log_debug_threed = new CheckBox (_panel, _("Debug: 3D"));
1585 t->Add (_log_debug_threed, 1, wxEXPAND | wxALL);
1586 _log_debug_encode = new CheckBox (_panel, _("Debug: encode"));
1587 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1588 _log_debug_email = new CheckBox (_panel, _("Debug: email sending"));
1589 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1590 _log_debug_video_view = new CheckBox (_panel, _("Debug: video view"));
1591 t->Add (_log_debug_video_view, 1, wxEXPAND | wxALL);
1592 _log_debug_player = new CheckBox (_panel, _("Debug: player"));
1593 t->Add (_log_debug_player, 1, wxEXPAND | wxALL);
1594 _log_debug_audio_analysis = new CheckBox (_panel, _("Debug: audio analysis"));
1595 t->Add (_log_debug_audio_analysis, 1, wxEXPAND | wxALL);
1596 table->Add (t, 0, wxALL, 6);
1599 #ifdef DCPOMATIC_WINDOWS
1600 _win32_console = new CheckBox (_panel, _("Open console window"));
1601 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1602 table->AddSpacer (0);
1605 _maximum_j2k_bandwidth->SetRange (1, 1000);
1606 _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1607 _video_display_mode->Append (_("Simple (safer)"));
1608 #if wxCHECK_VERSION(3, 1, 0)
1609 _video_display_mode->Append (_("OpenGL (faster)"));
1611 _video_display_mode->Bind (wxEVT_CHOICE, boost::bind(&AdvancedPage::video_display_mode_changed, this));
1612 _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1613 _allow_any_container->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_container_changed, this));
1614 _allow_96khz_audio->Bind (wxEVT_CHECKBOX, boost::bind(&AdvancedPage::allow_96khz_audio_changed, this));
1615 _use_all_audio_channels->Bind(wxEVT_CHECKBOX, boost::bind(&AdvancedPage::use_all_channels_changed, this));
1616 _show_experimental_audio_processors->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::show_experimental_audio_processors_changed, this));
1617 _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1618 _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
1619 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1620 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1621 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1622 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1623 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1624 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1625 _log_debug_threed->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1626 _log_debug_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1627 _log_debug_email->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1628 _log_debug_video_view->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1629 _log_debug_player->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1630 _log_debug_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1631 #ifdef DCPOMATIC_WINDOWS
1632 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::win32_console_changed, this));
1636 void config_changed () override
1638 auto config = Config::instance ();
1640 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1641 switch (config->video_view_type()) {
1642 case Config::VIDEO_VIEW_SIMPLE:
1643 checked_set (_video_display_mode, 0);
1645 case Config::VIDEO_VIEW_OPENGL:
1646 checked_set (_video_display_mode, 1);
1649 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1650 checked_set (_allow_any_container, config->allow_any_container ());
1651 checked_set (_allow_96khz_audio, config->allow_96khz_audio());
1652 checked_set (_use_all_audio_channels, config->use_all_audio_channels());
1653 checked_set (_show_experimental_audio_processors, config->show_experimental_audio_processors ());
1654 checked_set (_only_servers_encode, config->only_servers_encode ());
1655 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1656 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1657 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1658 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1659 checked_set (_log_debug_threed, config->log_types() & LogEntry::TYPE_DEBUG_THREE_D);
1660 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1661 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1662 checked_set (_log_debug_video_view, config->log_types() & LogEntry::TYPE_DEBUG_VIDEO_VIEW);
1663 checked_set (_log_debug_player, config->log_types() & LogEntry::TYPE_DEBUG_PLAYER);
1664 checked_set (_log_debug_audio_analysis, config->log_types() & LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS);
1665 checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
1666 #ifdef DCPOMATIC_WINDOWS
1667 checked_set (_win32_console, config->win32_console());
1671 void maximum_j2k_bandwidth_changed ()
1673 Config::instance()->set_maximum_j2k_bandwidth(_maximum_j2k_bandwidth->GetValue() * 1000000);
1676 void video_display_mode_changed ()
1678 if (_video_display_mode->GetSelection() == 0) {
1679 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_SIMPLE);
1681 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_OPENGL);
1685 void frames_in_memory_multiplier_changed ()
1687 Config::instance()->set_frames_in_memory_multiplier(_frames_in_memory_multiplier->GetValue());
1690 void allow_any_dcp_frame_rate_changed ()
1692 Config::instance()->set_allow_any_dcp_frame_rate(_allow_any_dcp_frame_rate->GetValue());
1695 void allow_any_container_changed ()
1697 Config::instance()->set_allow_any_container(_allow_any_container->GetValue());
1700 void allow_96khz_audio_changed ()
1702 Config::instance()->set_allow_96hhz_audio(_allow_96khz_audio->GetValue());
1705 void use_all_channels_changed ()
1707 Config::instance()->set_use_all_audio_channels(_use_all_audio_channels->GetValue());
1710 void show_experimental_audio_processors_changed ()
1712 Config::instance()->set_show_experimental_audio_processors(_show_experimental_audio_processors->GetValue());
1715 void only_servers_encode_changed ()
1717 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue());
1720 void dcp_metadata_filename_format_changed ()
1722 Config::instance()->set_dcp_metadata_filename_format(_dcp_metadata_filename_format->get());
1725 void dcp_asset_filename_format_changed ()
1727 Config::instance()->set_dcp_asset_filename_format(_dcp_asset_filename_format->get());
1733 if (_log_general->GetValue ()) {
1734 types |= LogEntry::TYPE_GENERAL;
1736 if (_log_warning->GetValue ()) {
1737 types |= LogEntry::TYPE_WARNING;
1739 if (_log_error->GetValue ()) {
1740 types |= LogEntry::TYPE_ERROR;
1742 if (_log_timing->GetValue ()) {
1743 types |= LogEntry::TYPE_TIMING;
1745 if (_log_debug_threed->GetValue ()) {
1746 types |= LogEntry::TYPE_DEBUG_THREE_D;
1748 if (_log_debug_encode->GetValue ()) {
1749 types |= LogEntry::TYPE_DEBUG_ENCODE;
1751 if (_log_debug_email->GetValue ()) {
1752 types |= LogEntry::TYPE_DEBUG_EMAIL;
1754 if (_log_debug_video_view->GetValue()) {
1755 types |= LogEntry::TYPE_DEBUG_VIDEO_VIEW;
1757 if (_log_debug_player->GetValue()) {
1758 types |= LogEntry::TYPE_DEBUG_PLAYER;
1760 if (_log_debug_audio_analysis->GetValue()) {
1761 types |= LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS;
1763 Config::instance()->set_log_types (types);
1766 #ifdef DCPOMATIC_WINDOWS
1767 void win32_console_changed ()
1769 Config::instance()->set_win32_console(_win32_console->GetValue());
1773 wxSpinCtrl* _maximum_j2k_bandwidth = nullptr;
1774 wxChoice* _video_display_mode = nullptr;
1775 wxSpinCtrl* _frames_in_memory_multiplier = nullptr;
1776 wxCheckBox* _allow_any_dcp_frame_rate = nullptr;
1777 wxCheckBox* _allow_any_container = nullptr;
1778 wxCheckBox* _allow_96khz_audio = nullptr;
1779 wxCheckBox* _use_all_audio_channels = nullptr;
1780 wxCheckBox* _show_experimental_audio_processors = nullptr;
1781 wxCheckBox* _only_servers_encode = nullptr;
1782 NameFormatEditor* _dcp_metadata_filename_format = nullptr;
1783 NameFormatEditor* _dcp_asset_filename_format = nullptr;
1784 wxCheckBox* _log_general = nullptr;
1785 wxCheckBox* _log_warning = nullptr;
1786 wxCheckBox* _log_error = nullptr;
1787 wxCheckBox* _log_timing = nullptr;
1788 wxCheckBox* _log_debug_threed = nullptr;
1789 wxCheckBox* _log_debug_encode = nullptr;
1790 wxCheckBox* _log_debug_email = nullptr;
1791 wxCheckBox* _log_debug_video_view = nullptr;
1792 wxCheckBox* _log_debug_player = nullptr;
1793 wxCheckBox* _log_debug_audio_analysis = nullptr;
1794 #ifdef DCPOMATIC_WINDOWS
1795 wxCheckBox* _win32_console = nullptr;
1800 wxPreferencesEditor*
1801 create_full_config_dialog ()
1803 auto e = new wxPreferencesEditor ();
1805 #ifdef DCPOMATIC_OSX
1806 /* Width that we force some of the config panels to be on OSX so that
1807 the containing window doesn't shrink too much when we select those panels.
1808 This is obviously an unpleasant hack.
1810 wxSize ps = wxSize (750, -1);
1811 int const border = 16;
1813 wxSize ps = wxSize (-1, -1);
1814 int const border = 8;
1817 e->AddPage (new FullGeneralPage (ps, border));
1818 e->AddPage (new SoundPage (ps, border));
1819 e->AddPage (new DefaultsPage (ps, border));
1820 e->AddPage (new EncodingServersPage(ps, border));
1821 e->AddPage (new KeysPage (ps, border));
1822 e->AddPage (new TMSPage (ps, border));
1823 e->AddPage (new EmailPage (ps, border));
1824 e->AddPage (new KDMEmailPage (ps, border));
1825 e->AddPage (new NotificationsPage (ps, border));
1826 e->AddPage (new CoverSheetPage (ps, border));
1827 e->AddPage (new IdentifiersPage (ps, border));
1828 e->AddPage (new AdvancedPage (ps, border));