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