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