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