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