3c480e37ed2b19ad58d00d1ec1e879867ffad8a7
[dcpomatic.git] / src / wx / player_config_dialog.cc
1 /*
2     Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
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.
10
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.
15
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/>.
18
19 */
20
21 /** @file src/player_config_dialog.cc
22  *  @brief A dialogue to edit DCP-o-matic Player configuration.
23  */
24
25 #include "config_dialog.h"
26 #include "wx_util.h"
27 #include "editable_list.h"
28 #include "filter_dialog.h"
29 #include "file_picker_ctrl.h"
30 #include "dir_picker_ctrl.h"
31 #include "server_dialog.h"
32 #include "make_chain_dialog.h"
33 #include "email_dialog.h"
34 #include "name_format_editor.h"
35 #include "nag_dialog.h"
36 #include "monitor_dialog.h"
37 #include "check_box.h"
38 #include "static_text.h"
39 #include "lib/config.h"
40 #include "lib/ratio.h"
41 #include "lib/filter.h"
42 #include "lib/dcp_content_type.h"
43 #include "lib/log.h"
44 #include "lib/util.h"
45 #include "lib/cross.h"
46 #include "lib/exceptions.h"
47 #include <dcp/locale_convert.h>
48 #include <dcp/exceptions.h>
49 #include <dcp/certificate_chain.h>
50 #include <wx/stdpaths.h>
51 #include <wx/preferences.h>
52 #include <wx/spinctrl.h>
53 #include <wx/filepicker.h>
54 #include <RtAudio.h>
55 #include <boost/filesystem.hpp>
56 #include <iostream>
57
58 using std::vector;
59 using std::string;
60 using std::list;
61 using std::cout;
62 using std::pair;
63 using std::make_pair;
64 using std::map;
65 using boost::bind;
66 using std::shared_ptr;
67 using boost::function;
68 using boost::optional;
69 #if BOOST_VERSION >= 106100
70 using namespace boost::placeholders;
71 #endif
72 using dcp::locale_convert;
73
74 class PlayerGeneralPage : public GeneralPage
75 {
76 public:
77         PlayerGeneralPage (wxSize panel_size, int border)
78                 : GeneralPage (panel_size, border)
79         {}
80
81 private:
82         void setup ()
83         {
84                 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
85                 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
86
87                 int r = 0;
88                 add_language_controls (table, r);
89                 add_update_controls (table, r);
90
91                 add_label_to_sizer (table, _panel, _("Start player as"), true, wxGBPosition(r, 0));
92                 _player_mode = new wxChoice (_panel, wxID_ANY);
93                 _player_mode->Append (_("window"));
94                 _player_mode->Append (_("full screen"));
95                 _player_mode->Append (_("full screen with controls on other monitor"));
96                 table->Add (_player_mode, wxGBPosition(r, 1));
97                 ++r;
98
99                 add_label_to_sizer (table, _panel, _("Dual-screen displays"), true, wxGBPosition(r, 0));
100                 _image_display = new wxChoice (_panel, wxID_ANY);
101                 _image_display->Append (_("Image on primary, controls on secondary"));
102                 _image_display->Append (_("Image on secondary, controls on primary"));
103                 table->Add (_image_display, wxGBPosition(r, 1));
104                 ++r;
105
106                 add_label_to_sizer (table, _panel, _("Video display mode"), true, wxGBPosition(r, 0));
107                 _video_display_mode = new wxChoice (_panel, wxID_ANY);
108                 _video_display_mode->Append (_("Simple (safer)"));
109                 _video_display_mode->Append (_("OpenGL (faster)"));
110                 table->Add (_video_display_mode, wxGBPosition(r, 1));
111                 ++r;
112
113                 wxStaticText* restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to change display mode)"), false, wxGBPosition(r, 0));
114                 wxFont font = restart->GetFont();
115                 font.SetStyle (wxFONTSTYLE_ITALIC);
116                 font.SetPointSize (font.GetPointSize() - 1);
117                 restart->SetFont (font);
118                 ++r;
119
120                 _respect_kdm = new CheckBox (_panel, _("Respect KDM validity periods"));
121                 table->Add (_respect_kdm, wxGBPosition(r, 0), wxGBSpan(1, 2));
122                 ++r;
123
124                 add_label_to_sizer (table, _panel, _("Activity log file"), true, wxGBPosition (r, 0));
125                 _activity_log_file = new FilePickerCtrl (_panel, _("Select activity log file"), "*", false, true);
126                 table->Add (_activity_log_file, wxGBPosition(r, 1));
127                 ++r;
128
129                 add_label_to_sizer (table, _panel, _("Debug log file"), true, wxGBPosition (r, 0));
130                 _debug_log_file = new FilePickerCtrl (_panel, _("Select debug log file"), "*", false, true);
131                 table->Add (_debug_log_file, wxGBPosition(r, 1));
132                 ++r;
133
134                 _player_mode->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::player_mode_changed, this));
135                 _image_display->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::image_display_changed, this));
136                 _video_display_mode->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::video_display_mode_changed, this));
137                 _respect_kdm->Bind (wxEVT_CHECKBOX, bind(&PlayerGeneralPage::respect_kdm_changed, this));
138                 _activity_log_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::activity_log_file_changed, this));
139                 _debug_log_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::debug_log_file_changed, this));
140         }
141
142         void config_changed ()
143         {
144                 GeneralPage::config_changed ();
145
146                 Config* config = Config::instance ();
147
148                 switch (config->player_mode()) {
149                 case Config::PLAYER_MODE_WINDOW:
150                         checked_set (_player_mode, 0);
151                         break;
152                 case Config::PLAYER_MODE_FULL:
153                         checked_set (_player_mode, 1);
154                         break;
155                 case Config::PLAYER_MODE_DUAL:
156                         checked_set (_player_mode, 2);
157                         break;
158                 }
159
160                 switch (config->video_view_type()) {
161                 case Config::VIDEO_VIEW_SIMPLE:
162                         checked_set (_video_display_mode, 0);
163                         break;
164                 case Config::VIDEO_VIEW_OPENGL:
165                         checked_set (_video_display_mode, 1);
166                         break;
167                 }
168
169                 checked_set (_image_display, config->image_display());
170                 checked_set (_respect_kdm, config->respect_kdm_validity_periods());
171                 if (config->player_activity_log_file()) {
172                         checked_set (_activity_log_file, *config->player_activity_log_file());
173                 }
174                 if (config->player_debug_log_file()) {
175                         checked_set (_debug_log_file, *config->player_debug_log_file());
176                 }
177         }
178
179 private:
180         void player_mode_changed ()
181         {
182                 switch (_player_mode->GetSelection()) {
183                 case 0:
184                         Config::instance()->set_player_mode(Config::PLAYER_MODE_WINDOW);
185                         break;
186                 case 1:
187                         Config::instance()->set_player_mode(Config::PLAYER_MODE_FULL);
188                         break;
189                 case 2:
190                         Config::instance()->set_player_mode(Config::PLAYER_MODE_DUAL);
191                         break;
192                 }
193         }
194
195         void image_display_changed ()
196         {
197                 Config::instance()->set_image_display(_image_display->GetSelection());
198         }
199
200         void video_display_mode_changed ()
201         {
202                 if (_video_display_mode->GetSelection() == 0) {
203                         Config::instance()->set_video_view_type (Config::VIDEO_VIEW_SIMPLE);
204                 } else {
205                         Config::instance()->set_video_view_type (Config::VIDEO_VIEW_OPENGL);
206                 }
207         }
208
209         void respect_kdm_changed ()
210         {
211                 Config::instance()->set_respect_kdm_validity_periods(_respect_kdm->GetValue());
212         }
213
214         void activity_log_file_changed ()
215         {
216                 Config::instance()->set_player_activity_log_file(wx_to_std(_activity_log_file->GetPath()));
217         }
218
219         void debug_log_file_changed ()
220         {
221                 Config::instance()->set_player_debug_log_file(wx_to_std(_debug_log_file->GetPath()));
222         }
223
224         wxChoice* _player_mode;
225         wxChoice* _image_display;
226         wxChoice* _video_display_mode;
227         wxCheckBox* _respect_kdm;
228         FilePickerCtrl* _activity_log_file;
229         FilePickerCtrl* _debug_log_file;
230 };
231
232
233 /** @class PlayerAdvancedPage
234  *  @brief Advanced page of the preferences dialog for the player.
235  */
236 class PlayerAdvancedPage : public Page
237 {
238 public:
239         PlayerAdvancedPage (wxSize panel_size, int border)
240                 : Page (panel_size, border)
241                 , _log_general (0)
242                 , _log_warning (0)
243                 , _log_error (0)
244                 , _log_timing (0)
245         {}
246
247         wxString GetName () const
248         {
249                 return _("Advanced");
250         }
251
252 #ifdef DCPOMATIC_OSX
253         wxBitmap GetLargeIcon () const
254         {
255                 return wxBitmap ("advanced", wxBITMAP_TYPE_PNG_RESOURCE);
256         }
257 #endif
258
259 private:
260         void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
261         {
262                 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
263 #ifdef __WXOSX__
264                 flags |= wxALIGN_RIGHT;
265                 text += wxT (":");
266 #endif
267                 wxStaticText* m = new StaticText (parent, text);
268                 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
269         }
270
271         void setup ()
272         {
273                 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
274                 table->AddGrowableCol (1, 1);
275                 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
276
277                 {
278                         add_top_aligned_label_to_sizer (table, _panel, _("Log"));
279                         wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
280                         _log_general = new CheckBox (_panel, _("General"));
281                         t->Add (_log_general, 1, wxEXPAND | wxALL);
282                         _log_warning = new CheckBox (_panel, _("Warnings"));
283                         t->Add (_log_warning, 1, wxEXPAND | wxALL);
284                         _log_error = new CheckBox (_panel, _("Errors"));
285                         t->Add (_log_error, 1, wxEXPAND | wxALL);
286                         /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
287                         _log_timing = new CheckBox (_panel, S_("Config|Timing"));
288                         t->Add (_log_timing, 1, wxEXPAND | wxALL);
289                         table->Add (t, 0, wxALL, 6);
290                 }
291
292 #ifdef DCPOMATIC_WINDOWS
293                 _win32_console = new CheckBox (_panel, _("Open console window"));
294                 table->Add (_win32_console, 1, wxEXPAND | wxALL);
295                 table->AddSpacer (0);
296 #endif
297
298                 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
299                 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
300                 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
301                 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::log_changed, this));
302 #ifdef DCPOMATIC_WINDOWS
303                 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&PlayerAdvancedPage::win32_console_changed, this));
304 #endif
305         }
306
307         void config_changed ()
308         {
309                 Config* config = Config::instance ();
310
311                 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
312                 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
313                 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
314                 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
315 #ifdef DCPOMATIC_WINDOWS
316                 checked_set (_win32_console, config->win32_console());
317 #endif
318         }
319
320         void log_changed ()
321         {
322                 int types = 0;
323                 if (_log_general->GetValue ()) {
324                         types |= LogEntry::TYPE_GENERAL;
325                 }
326                 if (_log_warning->GetValue ()) {
327                         types |= LogEntry::TYPE_WARNING;
328                 }
329                 if (_log_error->GetValue ())  {
330                         types |= LogEntry::TYPE_ERROR;
331                 }
332                 if (_log_timing->GetValue ()) {
333                         types |= LogEntry::TYPE_TIMING;
334                 }
335                 Config::instance()->set_log_types (types);
336         }
337
338 #ifdef DCPOMATIC_WINDOWS
339         void win32_console_changed ()
340         {
341                 Config::instance()->set_win32_console (_win32_console->GetValue ());
342         }
343 #endif
344
345         wxCheckBox* _log_general;
346         wxCheckBox* _log_warning;
347         wxCheckBox* _log_error;
348         wxCheckBox* _log_timing;
349 #ifdef DCPOMATIC_WINDOWS
350         wxCheckBox* _win32_console;
351 #endif
352 };
353
354
355 wxPreferencesEditor*
356 create_player_config_dialog ()
357 {
358         wxPreferencesEditor* e = new wxPreferencesEditor (_("DCP-o-matic Player Preferences"));
359
360 #ifdef DCPOMATIC_OSX
361         /* Width that we force some of the config panels to be on OSX so that
362            the containing window doesn't shrink too much when we select those panels.
363            This is obviously an unpleasant hack.
364         */
365         wxSize ps = wxSize (520, -1);
366         int const border = 16;
367 #else
368         wxSize ps = wxSize (-1, -1);
369         int const border = 8;
370 #endif
371
372         e->AddPage (new PlayerGeneralPage(wxSize(-1, 500), border));
373         e->AddPage (new SoundPage(ps, border));
374         e->AddPage (new LocationsPage(ps, border));
375         e->AddPage (new KeysPage(ps, border));
376         e->AddPage (new PlayerAdvancedPage(ps, border));
377         return e;
378 }