Choose some non-overlapping defaults for User Interaction modifier keys.
[ardour.git] / gtk2_ardour / rc_option_editor.cc
1 /*
2     Copyright (C) 2001-2011 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 #if !defined USE_CAIRO_IMAGE_SURFACE && !defined NDEBUG
25 #define OPTIONAL_CAIRO_IMAGE_SURFACE
26 #endif
27
28 #include <cairo/cairo.h>
29
30 #include <boost/algorithm/string.hpp>
31
32 #include <gtkmm/liststore.h>
33 #include <gtkmm/stock.h>
34 #include <gtkmm/scale.h>
35
36 #include <gtkmm2ext/utils.h>
37 #include <gtkmm2ext/slider_controller.h>
38 #include <gtkmm2ext/gtk_ui.h>
39 #include <gtkmm2ext/paths_dialog.h>
40 #include <gtkmm2ext/window_title.h>
41
42 #include "pbd/fpu.h"
43 #include "pbd/cpus.h"
44
45 #include "ardour/audioengine.h"
46 #include "ardour/profile.h"
47 #include "ardour/dB.h"
48 #include "ardour/rc_configuration.h"
49 #include "ardour/control_protocol_manager.h"
50 #include "ardour/plugin_manager.h"
51 #include "control_protocol/control_protocol.h"
52
53 #include "canvas/wave_view.h"
54
55 #include "ardour_window.h"
56 #include "ardour_dialog.h"
57 #include "ardour_ui.h"
58 #include "color_theme_manager.h"
59 #include "gui_thread.h"
60 #include "meter_patterns.h"
61 #include "midi_tracer.h"
62 #include "rc_option_editor.h"
63 #include "utils.h"
64 #include "midi_port_dialog.h"
65 #include "sfdb_ui.h"
66 #include "keyboard.h"
67 #include "theme_manager.h"
68 #include "ui_config.h"
69 #include "pbd/i18n.h"
70
71 using namespace std;
72 using namespace Gtk;
73 using namespace Gtkmm2ext;
74 using namespace PBD;
75 using namespace ARDOUR;
76 using namespace ARDOUR_UI_UTILS;
77
78 class ClickOptions : public OptionEditorBox
79 {
80 public:
81         ClickOptions (RCConfiguration* c)
82                 : _rc_config (c)
83                 , _click_browse_button (_("Browse..."))
84                 , _click_emphasis_browse_button (_("Browse..."))
85         {
86                 Table* t = manage (new Table (4, 3));
87                 t->set_spacings (4);
88
89                 Label* l = manage (left_aligned_label (_("Emphasis on first beat:")));
90                 t->attach (*l, 0, 1, 1, 2, FILL);
91                 t->attach (_use_emphasis_on_click_check_button, 1, 2, 1, 2, FILL);
92                 _use_emphasis_on_click_check_button.signal_toggled().connect (
93                     sigc::mem_fun (*this, &ClickOptions::use_emphasis_on_click_toggled));
94
95                 l = manage (left_aligned_label (_("Use default Click:")));
96                 t->attach (*l, 0, 1, 0, 1, FILL);
97                 t->attach (_use_default_click_check_button, 1, 2, 0, 1, FILL);
98                 _use_default_click_check_button.signal_toggled().connect (
99                     sigc::mem_fun (*this, &ClickOptions::use_default_click_toggled));
100
101                 l = manage (left_aligned_label (_("Click audio file:")));
102                 t->attach (*l, 0, 1, 2, 3, FILL);
103                 t->attach (_click_path_entry, 1, 2, 2, 3, FILL);
104                 _click_browse_button.signal_clicked ().connect (
105                     sigc::mem_fun (*this, &ClickOptions::click_browse_clicked));
106                 t->attach (_click_browse_button, 2, 3, 2, 3, FILL);
107
108                 l = manage (left_aligned_label (_("Click emphasis audio file:")));
109                 t->attach (*l, 0, 1, 3, 4, FILL);
110                 t->attach (_click_emphasis_path_entry, 1, 2, 3, 4, FILL);
111                 _click_emphasis_browse_button.signal_clicked ().connect (
112                     sigc::mem_fun (*this, &ClickOptions::click_emphasis_browse_clicked));
113                 t->attach (_click_emphasis_browse_button, 2, 3, 3, 4, FILL);
114
115                 _box->pack_start (*t, true, false);
116
117                 _click_path_entry.signal_activate().connect (sigc::mem_fun (*this, &ClickOptions::click_changed));
118                 _click_emphasis_path_entry.signal_activate().connect (sigc::mem_fun (*this, &ClickOptions::click_emphasis_changed));
119
120                 if (_rc_config->get_click_sound ().empty() &&
121                     _rc_config->get_click_emphasis_sound().empty()) {
122                         _use_default_click_check_button.set_active (true);
123                         _use_emphasis_on_click_check_button.set_active (true);
124
125                 } else {
126                         _use_default_click_check_button.set_active (false);
127                         _use_emphasis_on_click_check_button.set_active (false);
128                 }
129         }
130
131         void parameter_changed (string const & p)
132         {
133                 if (p == "click-sound") {
134                         _click_path_entry.set_text (_rc_config->get_click_sound());
135                 } else if (p == "click-emphasis-sound") {
136                         _click_emphasis_path_entry.set_text (_rc_config->get_click_emphasis_sound());
137                 } else if (p == "use-click-emphasis") {
138                         bool x = _rc_config->get_use_click_emphasis ();
139                         _use_emphasis_on_click_check_button.set_active (x);
140                 }
141         }
142
143         void set_state_from_config ()
144         {
145                 parameter_changed ("click-sound");
146                 parameter_changed ("click-emphasis-sound");
147                 parameter_changed ("use-click-emphasis");
148         }
149
150 private:
151
152         void click_browse_clicked ()
153         {
154                 SoundFileChooser sfdb (_("Choose Click"));
155
156                 sfdb.show_all ();
157                 sfdb.present ();
158
159                 if (sfdb.run () == RESPONSE_OK) {
160                         click_chosen (sfdb.get_filename());
161                 }
162         }
163
164         void click_chosen (string const & path)
165         {
166                 _click_path_entry.set_text (path);
167                 _rc_config->set_click_sound (path);
168         }
169
170         void click_changed ()
171         {
172                 click_chosen (_click_path_entry.get_text ());
173         }
174
175         void click_emphasis_browse_clicked ()
176         {
177                 SoundFileChooser sfdb (_("Choose Click Emphasis"));
178
179                 sfdb.show_all ();
180                 sfdb.present ();
181
182                 if (sfdb.run () == RESPONSE_OK) {
183                         click_emphasis_chosen (sfdb.get_filename());
184                 }
185         }
186
187         void click_emphasis_chosen (string const & path)
188         {
189                 _click_emphasis_path_entry.set_text (path);
190                 _rc_config->set_click_emphasis_sound (path);
191         }
192
193         void click_emphasis_changed ()
194         {
195                 click_emphasis_chosen (_click_emphasis_path_entry.get_text ());
196         }
197
198         void use_default_click_toggled ()
199         {
200                 if (_use_default_click_check_button.get_active ()) {
201                         _rc_config->set_click_sound ("");
202                         _rc_config->set_click_emphasis_sound ("");
203                         _click_path_entry.set_sensitive (false);
204                         _click_emphasis_path_entry.set_sensitive (false);
205                         _click_browse_button.set_sensitive (false);
206                         _click_emphasis_browse_button.set_sensitive (false);
207                 } else {
208                         _click_path_entry.set_sensitive (true);
209                         _click_emphasis_path_entry.set_sensitive (true);
210                         _click_browse_button.set_sensitive (true);
211                         _click_emphasis_browse_button.set_sensitive (true);
212                 }
213         }
214
215         void use_emphasis_on_click_toggled ()
216         {
217                 if (_use_emphasis_on_click_check_button.get_active ()) {
218                         _rc_config->set_use_click_emphasis(true);
219                 } else {
220                         _rc_config->set_use_click_emphasis(false);
221                 }
222         }
223
224         RCConfiguration* _rc_config;
225         CheckButton _use_default_click_check_button;
226         CheckButton _use_emphasis_on_click_check_button;
227         Entry _click_path_entry;
228         Entry _click_emphasis_path_entry;
229         Button _click_browse_button;
230         Button _click_emphasis_browse_button;
231 };
232
233 class UndoOptions : public OptionEditorBox
234 {
235 public:
236         UndoOptions (RCConfiguration* c) :
237                 _rc_config (c),
238                 _limit_undo_button (_("Limit undo history to")),
239                 _save_undo_button (_("Save undo history of"))
240         {
241                 Table* t = new Table (2, 3);
242                 t->set_spacings (4);
243
244                 t->attach (_limit_undo_button, 0, 1, 0, 1, FILL);
245                 _limit_undo_spin.set_range (0, 512);
246                 _limit_undo_spin.set_increments (1, 10);
247                 t->attach (_limit_undo_spin, 1, 2, 0, 1, FILL | EXPAND);
248                 Label* l = manage (left_aligned_label (_("commands")));
249                 t->attach (*l, 2, 3, 0, 1);
250
251                 t->attach (_save_undo_button, 0, 1, 1, 2, FILL);
252                 _save_undo_spin.set_range (0, 512);
253                 _save_undo_spin.set_increments (1, 10);
254                 t->attach (_save_undo_spin, 1, 2, 1, 2, FILL | EXPAND);
255                 l = manage (left_aligned_label (_("commands")));
256                 t->attach (*l, 2, 3, 1, 2);
257
258                 _box->pack_start (*t);
259
260                 _limit_undo_button.signal_toggled().connect (sigc::mem_fun (*this, &UndoOptions::limit_undo_toggled));
261                 _limit_undo_spin.signal_value_changed().connect (sigc::mem_fun (*this, &UndoOptions::limit_undo_changed));
262                 _save_undo_button.signal_toggled().connect (sigc::mem_fun (*this, &UndoOptions::save_undo_toggled));
263                 _save_undo_spin.signal_value_changed().connect (sigc::mem_fun (*this, &UndoOptions::save_undo_changed));
264         }
265
266         void parameter_changed (string const & p)
267         {
268                 if (p == "history-depth") {
269                         int32_t const d = _rc_config->get_history_depth();
270                         _limit_undo_button.set_active (d != 0);
271                         _limit_undo_spin.set_sensitive (d != 0);
272                         _limit_undo_spin.set_value (d);
273                 } else if (p == "save-history") {
274                         bool const x = _rc_config->get_save_history ();
275                         _save_undo_button.set_active (x);
276                         _save_undo_spin.set_sensitive (x);
277                 } else if (p == "save-history-depth") {
278                         _save_undo_spin.set_value (_rc_config->get_saved_history_depth());
279                 }
280         }
281
282         void set_state_from_config ()
283         {
284                 parameter_changed ("save-history");
285                 parameter_changed ("history-depth");
286                 parameter_changed ("save-history-depth");
287         }
288
289         void limit_undo_toggled ()
290         {
291                 bool const x = _limit_undo_button.get_active ();
292                 _limit_undo_spin.set_sensitive (x);
293                 int32_t const n = x ? 16 : 0;
294                 _limit_undo_spin.set_value (n);
295                 _rc_config->set_history_depth (n);
296         }
297
298         void limit_undo_changed ()
299         {
300                 _rc_config->set_history_depth (_limit_undo_spin.get_value_as_int ());
301         }
302
303         void save_undo_toggled ()
304         {
305                 bool const x = _save_undo_button.get_active ();
306                 _rc_config->set_save_history (x);
307         }
308
309         void save_undo_changed ()
310         {
311                 _rc_config->set_saved_history_depth (_save_undo_spin.get_value_as_int ());
312         }
313
314 private:
315         RCConfiguration* _rc_config;
316         CheckButton _limit_undo_button;
317         SpinButton _limit_undo_spin;
318         CheckButton _save_undo_button;
319         SpinButton _save_undo_spin;
320 };
321
322
323
324 static const struct {
325     const char *name;
326     guint modifier;
327 } modifiers[] = {
328
329         { "Unmodified", 0 },
330
331 #ifdef __APPLE__
332
333         /* Command = Meta
334            Option/Alt = Mod1
335         */
336         { "Key|Shift", GDK_SHIFT_MASK },
337         { "Command", GDK_MOD2_MASK },
338         { "Control", GDK_CONTROL_MASK },
339         { "Option", GDK_MOD1_MASK },
340         { "Command-Shift", GDK_MOD2_MASK|GDK_SHIFT_MASK },
341         { "Command-Option", GDK_MOD2_MASK|GDK_MOD1_MASK },
342         { "Command-Control", GDK_MOD2_MASK|GDK_CONTROL_MASK },
343         { "Command-Option-Control", GDK_MOD2_MASK|GDK_MOD1_MASK|GDK_CONTROL_MASK },
344         { "Option-Control", GDK_MOD1_MASK|GDK_CONTROL_MASK },
345         { "Option-Shift", GDK_MOD1_MASK|GDK_SHIFT_MASK },
346         { "Control-Shift", GDK_CONTROL_MASK|GDK_SHIFT_MASK },
347         { "Shift-Command-Option", GDK_MOD5_MASK|GDK_SHIFT_MASK|GDK_MOD2_MASK },
348
349 #else
350         { "Key|Shift", GDK_SHIFT_MASK },
351         { "Control", GDK_CONTROL_MASK },
352         { "Alt", GDK_MOD1_MASK },
353         { "Control-Shift", GDK_CONTROL_MASK|GDK_SHIFT_MASK },
354         { "Control-Alt", GDK_CONTROL_MASK|GDK_MOD1_MASK },
355         { "Control-Windows", GDK_CONTROL_MASK|GDK_MOD4_MASK },
356         { "Control-Shift-Alt", GDK_CONTROL_MASK|GDK_SHIFT_MASK|GDK_MOD1_MASK },
357         { "Alt-Windows", GDK_MOD1_MASK|GDK_MOD4_MASK },
358         { "Alt-Shift", GDK_MOD1_MASK|GDK_SHIFT_MASK },
359         { "Alt-Shift-Windows", GDK_MOD1_MASK|GDK_SHIFT_MASK|GDK_MOD4_MASK },
360         { "Mod2", GDK_MOD2_MASK },
361         { "Mod3", GDK_MOD3_MASK },
362         { "Windows", GDK_MOD4_MASK },
363         { "Mod5", GDK_MOD5_MASK },
364 #endif
365         { 0, 0 }
366 };
367
368
369 class KeyboardOptions : public OptionEditorBox
370 {
371 public:
372         KeyboardOptions () :
373                   _delete_button_adjustment (3, 1, 12),
374                   _delete_button_spin (_delete_button_adjustment),
375                   _edit_button_adjustment (3, 1, 5),
376                   _edit_button_spin (_edit_button_adjustment),
377                   _insert_note_button_adjustment (3, 1, 5),
378                   _insert_note_button_spin (_insert_note_button_adjustment)
379         {
380                 const std::string restart_msg = _("\nChanges to this setting will only persist after your project has been saved.");
381                 /* internationalize and prepare for use with combos */
382
383                 vector<string> dumb;
384                 for (int i = 0; modifiers[i].name; ++i) {
385                         dumb.push_back (S_(modifiers[i].name));
386                 }
387
388                 set_popdown_strings (_edit_modifier_combo, dumb);
389                 _edit_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::edit_modifier_chosen));
390                 Gtkmm2ext::UI::instance()->set_tip (_edit_modifier_combo,
391                                                     (string_compose (_("<b>Recommended Setting: %1 + button 3 (right mouse button)</b>%2"),  Keyboard::primary_modifier_name (), restart_msg)));
392                 for (int x = 0; modifiers[x].name; ++x) {
393                         if (modifiers[x].modifier == Keyboard::edit_modifier ()) {
394                                 _edit_modifier_combo.set_active_text (S_(modifiers[x].name));
395                                 break;
396                         }
397                 }
398
399                 Table* t = manage (new Table (5, 11));
400                 t->set_spacings (4);
401
402                 int row = 0;
403                 int col = 0;
404
405                 Label* l = manage (left_aligned_label (_("Select Keyboard layout:")));
406                 l->set_name ("OptionsLabel");
407
408                 vector<string> strs;
409
410                 for (map<string,string>::iterator bf = Keyboard::binding_files.begin(); bf != Keyboard::binding_files.end(); ++bf) {
411                         strs.push_back (bf->first);
412                 }
413
414                 set_popdown_strings (_keyboard_layout_selector, strs);
415                 _keyboard_layout_selector.set_active_text (Keyboard::current_binding_name());
416                 _keyboard_layout_selector.signal_changed().connect (sigc::mem_fun (*this, &KeyboardOptions::bindings_changed));
417
418                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
419                 t->attach (_keyboard_layout_selector, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
420
421                 ++row;
422                 col = 0;
423
424                 l = manage (left_aligned_label (_("When Clicking:")));
425                 l->set_name ("OptionEditorHeading");
426                 t->attach (*l, col, col + 2, row, row + 1, FILL | EXPAND, FILL);
427
428                 ++row;
429                 col = 1;
430
431                 l = manage (left_aligned_label (_("Edit using:")));
432                 l->set_name ("OptionsLabel");
433
434                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
435                 t->attach (_edit_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
436
437                 l = manage (new Label (_("+ button")));
438                 l->set_name ("OptionsLabel");
439
440                 t->attach (*l, col + 3, col + 4, row, row + 1, FILL | EXPAND, FILL);
441                 t->attach (_edit_button_spin, col + 4, col + 5, row, row + 1, FILL | EXPAND, FILL);
442
443                 _edit_button_spin.set_name ("OptionsEntry");
444                 _edit_button_adjustment.set_value (Keyboard::edit_button());
445                 _edit_button_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::edit_button_changed));
446
447                 ++row;
448                 col = 1;
449
450                 set_popdown_strings (_delete_modifier_combo, dumb);
451                 _delete_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::delete_modifier_chosen));
452                 Gtkmm2ext::UI::instance()->set_tip (_delete_modifier_combo,
453                                                     (string_compose (_("<b>Recommended Setting: %1 + button 3 (right mouse button)</b>%2"), Keyboard::tertiary_modifier_name (), restart_msg)));
454                 for (int x = 0; modifiers[x].name; ++x) {
455                         if (modifiers[x].modifier == Keyboard::delete_modifier ()) {
456                                 _delete_modifier_combo.set_active_text (S_(modifiers[x].name));
457                                 break;
458                         }
459                 }
460
461                 l = manage (left_aligned_label (_("Delete using:")));
462                 l->set_name ("OptionsLabel");
463
464                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
465                 t->attach (_delete_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
466
467                 l = manage (new Label (_("+ button")));
468                 l->set_name ("OptionsLabel");
469
470                 t->attach (*l, col + 3, col + 4, row, row + 1, FILL | EXPAND, FILL);
471                 t->attach (_delete_button_spin, col + 4, col + 5, row, row + 1, FILL | EXPAND, FILL);
472
473                 _delete_button_spin.set_name ("OptionsEntry");
474                 _delete_button_adjustment.set_value (Keyboard::delete_button());
475                 _delete_button_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::delete_button_changed));
476
477                 ++row;
478                 col = 1;
479
480                 set_popdown_strings (_insert_note_modifier_combo, dumb);
481                 _insert_note_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::insert_note_modifier_chosen));
482                 Gtkmm2ext::UI::instance()->set_tip (_insert_note_modifier_combo,
483                                                     (string_compose (_("<b>Recommended Setting: %1 + button 1 (left mouse button)</b>%2"), Keyboard::primary_modifier_name (), restart_msg)));
484                 for (int x = 0; modifiers[x].name; ++x) {
485                         if (modifiers[x].modifier == Keyboard::insert_note_modifier ()) {
486                                 _insert_note_modifier_combo.set_active_text (S_(modifiers[x].name));
487                                 break;
488                         }
489                 }
490
491                 l = manage (left_aligned_label (_("Insert note using:")));
492                 l->set_name ("OptionsLabel");
493
494                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
495                 t->attach (_insert_note_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
496
497                 l = manage (new Label (_("+ button")));
498                 l->set_name ("OptionsLabel");
499
500                 t->attach (*l, col + 3, col + 4, row, row + 1, FILL | EXPAND, FILL);
501                 t->attach (_insert_note_button_spin, col + 4, col + 5, row, row + 1, FILL | EXPAND, FILL);
502
503                 _insert_note_button_spin.set_name ("OptionsEntry");
504                 _insert_note_button_adjustment.set_value (Keyboard::insert_note_button());
505                 _insert_note_button_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::insert_note_button_changed));
506
507                 ++row;
508
509                 l = manage (left_aligned_label (_("When Beginning a Drag:")));
510                 l->set_name ("OptionEditorHeading");
511                 t->attach (*l, 0, 2, row, row + 1, FILL | EXPAND, FILL);
512
513                 ++row;
514                 col = 1;
515
516                 /* copy modifier */
517                 set_popdown_strings (_copy_modifier_combo, dumb);
518                 _copy_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::copy_modifier_chosen));
519                 Gtkmm2ext::UI::instance()->set_tip (_copy_modifier_combo,
520                                                     (string_compose (_("<b>Recommended Setting: %1</b>%2"),
521 #ifdef __APPLE__
522                                                                      Keyboard::secondary_modifier_name (),
523 #else
524                                                                      Keyboard::primary_modifier_name (),
525 #endif
526                                                                      restart_msg)));
527                 for (int x = 0; modifiers[x].name; ++x) {
528                         if (modifiers[x].modifier == (guint) Keyboard::CopyModifier) {
529                                 _copy_modifier_combo.set_active_text (S_(modifiers[x].name));
530                                 break;
531                         }
532                 }
533
534                 l = manage (left_aligned_label (_("Copy items using:")));
535                 l->set_name ("OptionsLabel");
536
537                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
538                 t->attach (_copy_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
539
540                                 ++row;
541                 col = 1;
542
543                 /* constraint modifier */
544                 set_popdown_strings (_constraint_modifier_combo, dumb);
545                 _constraint_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::constraint_modifier_chosen));
546                 Gtkmm2ext::UI::instance()->set_tip (_constraint_modifier_combo,
547                                                     (string_compose (_("<b>Recommended Setting: %1</b>%2"),
548 #ifdef __APPLE__
549                                                                      Keyboard::primary_modifier_name (),
550 #else
551                                                                      Keyboard::secondary_modifier_name (),
552 #endif
553                                                                      restart_msg)));
554                 for (int x = 0; modifiers[x].name; ++x) {
555                         if (modifiers[x].modifier == (guint) ArdourKeyboard::constraint_modifier ()) {
556                                 _constraint_modifier_combo.set_active_text (S_(modifiers[x].name));
557                                 break;
558                         }
559                 }
560
561                 l = manage (left_aligned_label (_("Constrain drag using:")));
562                 l->set_name ("OptionsLabel");
563
564                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
565                 t->attach (_constraint_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
566
567                 ++row;
568                 col = 1;
569
570                 /* push points */
571                 set_popdown_strings (_push_points_combo, dumb);
572                 _push_points_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::push_points_modifier_chosen));
573
574                 Gtkmm2ext::UI::instance()->set_tip (_push_points_combo,
575                                                     (string_compose (_("<b>Recommended Setting: %1</b>%2"), Keyboard::primary_modifier_name (), restart_msg)));
576                 for (int x = 0; modifiers[x].name; ++x) {
577                         if (modifiers[x].modifier == (guint) ArdourKeyboard::push_points_modifier ()) {
578                                 _push_points_combo.set_active_text (S_(modifiers[x].name));
579                                 break;
580                         }
581                 }
582
583                 l = manage (left_aligned_label (_("Push points using:")));
584                 l->set_name ("OptionsLabel");
585
586                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
587                 t->attach (_push_points_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
588
589                 ++row;
590
591                 l = manage (left_aligned_label (_("When Beginning a Trim:")));
592                 l->set_name ("OptionEditorHeading");
593                 t->attach (*l, 0, 2, row, row + 1, FILL | EXPAND, FILL);
594
595                 ++row;
596                 col = 1;
597
598                 /* trim_contents */
599                 set_popdown_strings (_trim_contents_combo, dumb);
600                 _trim_contents_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::trim_contents_modifier_chosen));
601                 Gtkmm2ext::UI::instance()->set_tip (_trim_contents_combo,
602                                                     (string_compose (_("<b>Recommended Setting: %1</b>%2"), Keyboard::primary_modifier_name (), restart_msg)));
603                 for (int x = 0; modifiers[x].name; ++x) {
604                         if (modifiers[x].modifier == (guint) ArdourKeyboard::trim_contents_modifier ()) {
605                                 _trim_contents_combo.set_active_text (S_(modifiers[x].name));
606                                 break;
607                         }
608                 }
609
610                 l = manage (left_aligned_label (_("Trim contents using:")));
611                 l->set_name ("OptionsLabel");
612
613                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
614                 t->attach (_trim_contents_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
615
616                 ++row;
617                 col = 1;
618
619                 /* anchored trim */
620                 set_popdown_strings (_trim_anchored_combo, dumb);
621                 _trim_anchored_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::trim_anchored_modifier_chosen));
622                 Gtkmm2ext::UI::instance()->set_tip (_trim_anchored_combo,
623                                                     (string_compose (_("<b>Recommended Setting: %1</b>%2"), Keyboard::tertiary_modifier_name (), restart_msg)));
624                 for (int x = 0; modifiers[x].name; ++x) {
625                         if (modifiers[x].modifier == (guint) ArdourKeyboard::trim_anchored_modifier ()) {
626                                 _trim_anchored_combo.set_active_text (S_(modifiers[x].name));
627                                 break;
628                         }
629                 }
630
631                 l = manage (left_aligned_label (_("Anchored trim using:")));
632                 l->set_name ("OptionsLabel");
633
634                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
635                 ++col;
636                 t->attach (_trim_anchored_combo, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
637
638                 ++row;
639                 col = 1;
640
641                 /* jump trim disabled for now
642                 set_popdown_strings (_trim_jump_combo, dumb);
643                 _trim_jump_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::trim_jump_modifier_chosen));
644
645                 for (int x = 0; modifiers[x].name; ++x) {
646                         if (modifiers[x].modifier == (guint) Keyboard::trim_jump_modifier ()) {
647                                 _trim_jump_combo.set_active_text (S_(modifiers[x].name));
648                                 break;
649                         }
650                 }
651
652                 l = manage (left_aligned_label (_("Jump after trim using:")));
653                 l->set_name ("OptionsLabel");
654
655                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
656                 ++col;
657                 t->attach (_trim_jump_combo, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
658
659                 ++row;
660                 col = 1;
661                 */
662
663                 /* note resize relative */
664                 set_popdown_strings (_note_size_relative_combo, dumb);
665                 _note_size_relative_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::note_size_relative_modifier_chosen));
666                 Gtkmm2ext::UI::instance()->set_tip (_note_size_relative_combo,
667                                                     (string_compose (_("<b>Recommended Setting: %1</b>%2"), Keyboard::primary_modifier_name (), restart_msg)));
668                 for (int x = 0; modifiers[x].name; ++x) {
669                         if (modifiers[x].modifier == (guint) ArdourKeyboard::note_size_relative_modifier ()) {
670                                 _note_size_relative_combo.set_active_text (S_(modifiers[x].name));
671                                 break;
672                         }
673                 }
674
675                 l = manage (left_aligned_label (_("Resize notes relatively using:")));
676                 l->set_name ("OptionsLabel");
677
678                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
679                 ++col;
680                 t->attach (_note_size_relative_combo, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
681
682                 ++row;
683
684                 l = manage (left_aligned_label (_("While Dragging:")));
685                 l->set_name ("OptionEditorHeading");
686                 t->attach (*l, 0, 2, row, row + 1, FILL | EXPAND, FILL);
687
688                 ++row;
689                 col = 1;
690
691                 /* ignore snap */
692                 set_popdown_strings (_snap_modifier_combo, dumb);
693                 _snap_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::snap_modifier_chosen));
694 #ifdef __APPLE__
695                 std::string mod_str = string_compose (X_("%1-%2"), Keyboard::level4_modifier_name (), Keyboard::tertiary_modifier_name ());
696 #else
697                 std::string mod_str = Keyboard::secondary_modifier_name();
698 #endif
699                 Gtkmm2ext::UI::instance()->set_tip (_snap_modifier_combo,
700                                                     (string_compose (_("<b>Recommended Setting: %1</b>%2"), mod_str, restart_msg)));
701                 for (int x = 0; modifiers[x].name; ++x) {
702                         if (modifiers[x].modifier == (guint) Keyboard::snap_modifier ()) {
703                                 _snap_modifier_combo.set_active_text (S_(modifiers[x].name));
704                                 break;
705                         }
706                 }
707
708                 l = manage (left_aligned_label (_("Ignore snap using:")));
709                 l->set_name ("OptionsLabel");
710
711                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
712                 t->attach (_snap_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
713
714                 ++row;
715                 col = 1;
716
717                 /* snap delta */
718                 set_popdown_strings (_snap_delta_combo, dumb);
719                 _snap_delta_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::snap_delta_modifier_chosen));
720 #ifdef __APPLE__
721                 mod_str = Keyboard::level4_modifier_name ();
722 #else
723                 mod_str = string_compose (X_("%1-%2"), Keyboard::secondary_modifier_name (), Keyboard::level4_modifier_name ());
724 #endif
725                 Gtkmm2ext::UI::instance()->set_tip (_snap_delta_combo,
726                                                     (string_compose (_("<b>Recommended Setting: %1</b>%2"), mod_str, restart_msg)));
727                 for (int x = 0; modifiers[x].name; ++x) {
728                         if (modifiers[x].modifier == (guint) Keyboard::snap_delta_modifier ()) {
729                                 _snap_delta_combo.set_active_text (S_(modifiers[x].name));
730                                 break;
731                         }
732                 }
733
734                 l = manage (left_aligned_label (_("Snap relatively using:")));
735                 l->set_name ("OptionsLabel");
736
737                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
738                 t->attach (_snap_delta_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
739
740                 ++row;
741
742                 l = manage (left_aligned_label (_("While Trimming:")));
743                 l->set_name ("OptionEditorHeading");
744                 t->attach (*l, 0, 2, row, row + 1, FILL | EXPAND, FILL);
745
746                 ++row;
747                 col = 1;
748
749                 /* trim_overlap */
750                 set_popdown_strings (_trim_overlap_combo, dumb);
751                 _trim_overlap_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::trim_overlap_modifier_chosen));
752
753                 Gtkmm2ext::UI::instance()->set_tip (_trim_overlap_combo,
754                                                     (string_compose (_("<b>Recommended Setting: %1</b>%2"), Keyboard::tertiary_modifier_name (), restart_msg)));
755                 for (int x = 0; modifiers[x].name; ++x) {
756                         if (modifiers[x].modifier == (guint) ArdourKeyboard::trim_overlap_modifier ()) {
757                                 _trim_overlap_combo.set_active_text (S_(modifiers[x].name));
758                                 break;
759                         }
760                 }
761
762                 l = manage (left_aligned_label (_("Resize overlapped regions using:")));
763                 l->set_name ("OptionsLabel");
764
765                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
766                 t->attach (_trim_overlap_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
767
768                 ++row;
769
770                 l = manage (left_aligned_label (_("While Dragging Control Points:")));
771                 l->set_name ("OptionEditorHeading");
772                 t->attach (*l, 0, 2, row, row + 1, FILL | EXPAND, FILL);
773
774                 ++row;
775                 col = 1;
776
777                 /* fine adjust */
778                 set_popdown_strings (_fine_adjust_combo, dumb);
779                 _fine_adjust_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::fine_adjust_modifier_chosen));
780
781                 mod_str = string_compose (X_("%1-%2"), Keyboard::secondary_modifier_name (), Keyboard::tertiary_modifier_name ());
782                 Gtkmm2ext::UI::instance()->set_tip (_fine_adjust_combo,
783                                                     (string_compose (_("<b>Recommended Setting: %1</b>%2"), mod_str, restart_msg)));
784                 for (int x = 0; modifiers[x].name; ++x) {
785                         if (modifiers[x].modifier == (guint) ArdourKeyboard::fine_adjust_modifier ()) {
786                                 _fine_adjust_combo.set_active_text (S_(modifiers[x].name));
787                                 break;
788                         }
789                 }
790
791                 l = manage (left_aligned_label (_("Fine adjust using:")));
792                 l->set_name ("OptionsLabel");
793
794                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
795                 t->attach (_fine_adjust_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
796
797                 _box->pack_start (*t, false, false);
798         }
799
800         void parameter_changed (string const &)
801         {
802                 /* XXX: these aren't really config options... */
803         }
804
805         void set_state_from_config ()
806         {
807                 /* XXX: these aren't really config options... */
808         }
809
810 private:
811
812         void bindings_changed ()
813         {
814                 string const txt = _keyboard_layout_selector.get_active_text();
815
816                 /* XXX: config...?  for all this keyboard stuff */
817
818                 for (map<string,string>::iterator i = Keyboard::binding_files.begin(); i != Keyboard::binding_files.end(); ++i) {
819                         if (txt == i->first) {
820                                 if (Keyboard::load_keybindings (i->second)) {
821                                         Keyboard::save_keybindings ();
822                                 }
823                         }
824                 }
825         }
826
827         void edit_modifier_chosen ()
828         {
829                 string const txt = _edit_modifier_combo.get_active_text();
830
831                 for (int i = 0; modifiers[i].name; ++i) {
832                         if (txt == S_(modifiers[i].name)) {
833                                 Keyboard::set_edit_modifier (modifiers[i].modifier);
834                                 break;
835                         }
836                 }
837         }
838
839         void delete_modifier_chosen ()
840         {
841                 string const txt = _delete_modifier_combo.get_active_text();
842
843                 for (int i = 0; modifiers[i].name; ++i) {
844                         if (txt == S_(modifiers[i].name)) {
845                                 Keyboard::set_delete_modifier (modifiers[i].modifier);
846                                 break;
847                         }
848                 }
849         }
850
851         void copy_modifier_chosen ()
852         {
853                 string const txt = _copy_modifier_combo.get_active_text();
854
855                 for (int i = 0; modifiers[i].name; ++i) {
856                         if (txt == S_(modifiers[i].name)) {
857                                 Keyboard::set_copy_modifier (modifiers[i].modifier);
858                                 break;
859                         }
860                 }
861         }
862
863         void insert_note_modifier_chosen ()
864         {
865                 string const txt = _insert_note_modifier_combo.get_active_text();
866
867                 for (int i = 0; modifiers[i].name; ++i) {
868                         if (txt == S_(modifiers[i].name)) {
869                                 Keyboard::set_insert_note_modifier (modifiers[i].modifier);
870                                 break;
871                         }
872                 }
873         }
874
875         void snap_modifier_chosen ()
876         {
877                 string const txt = _snap_modifier_combo.get_active_text();
878
879                 for (int i = 0; modifiers[i].name; ++i) {
880                         if (txt == S_(modifiers[i].name)) {
881                                 Keyboard::set_snap_modifier (modifiers[i].modifier);
882                                 break;
883                         }
884                 }
885         }
886
887         void snap_delta_modifier_chosen ()
888         {
889                 string const txt = _snap_delta_combo.get_active_text();
890
891                 for (int i = 0; modifiers[i].name; ++i) {
892                         if (txt == S_(modifiers[i].name)) {
893                                 Keyboard::set_snap_delta_modifier (modifiers[i].modifier);
894                                 break;
895                         }
896                 }
897         }
898
899         void constraint_modifier_chosen ()
900         {
901                 string const txt = _constraint_modifier_combo.get_active_text();
902
903                 for (int i = 0; modifiers[i].name; ++i) {
904                         if (txt == S_(modifiers[i].name)) {
905                                 ArdourKeyboard::set_constraint_modifier (modifiers[i].modifier);
906                                 break;
907                         }
908                 }
909         }
910
911         void trim_contents_modifier_chosen ()
912         {
913                 string const txt = _trim_contents_combo.get_active_text();
914
915                 for (int i = 0; modifiers[i].name; ++i) {
916                         if (txt == S_(modifiers[i].name)) {
917                                 ArdourKeyboard::set_trim_contents_modifier (modifiers[i].modifier);
918                                 break;
919                         }
920                 }
921         }
922
923         void trim_overlap_modifier_chosen ()
924         {
925                 string const txt = _trim_overlap_combo.get_active_text();
926
927                 for (int i = 0; modifiers[i].name; ++i) {
928                         if (txt == S_(modifiers[i].name)) {
929                                 ArdourKeyboard::set_trim_overlap_modifier (modifiers[i].modifier);
930                                 break;
931                         }
932                 }
933         }
934
935         void trim_anchored_modifier_chosen ()
936         {
937                 string const txt = _trim_anchored_combo.get_active_text();
938
939                 for (int i = 0; modifiers[i].name; ++i) {
940                         if (txt == S_(modifiers[i].name)) {
941                                 ArdourKeyboard::set_trim_anchored_modifier (modifiers[i].modifier);
942                                 break;
943                         }
944                 }
945         }
946
947         void fine_adjust_modifier_chosen ()
948         {
949                 string const txt = _fine_adjust_combo.get_active_text();
950
951                 for (int i = 0; modifiers[i].name; ++i) {
952                         if (txt == S_(modifiers[i].name)) {
953                                 ArdourKeyboard::set_fine_adjust_modifier (modifiers[i].modifier);
954                                 break;
955                         }
956                 }
957         }
958
959         void push_points_modifier_chosen ()
960         {
961                 string const txt = _push_points_combo.get_active_text();
962
963                 for (int i = 0; modifiers[i].name; ++i) {
964                         if (txt == S_(modifiers[i].name)) {
965                                 ArdourKeyboard::set_push_points_modifier (modifiers[i].modifier);
966                                 break;
967                         }
968                 }
969         }
970
971         void note_size_relative_modifier_chosen ()
972         {
973                 string const txt = _note_size_relative_combo.get_active_text();
974
975                 for (int i = 0; modifiers[i].name; ++i) {
976                         if (txt == S_(modifiers[i].name)) {
977                                 ArdourKeyboard::set_note_size_relative_modifier (modifiers[i].modifier);
978                                 break;
979                         }
980                 }
981         }
982
983         void delete_button_changed ()
984         {
985                 Keyboard::set_delete_button (_delete_button_spin.get_value_as_int());
986         }
987
988         void edit_button_changed ()
989         {
990                 Keyboard::set_edit_button (_edit_button_spin.get_value_as_int());
991         }
992
993         void insert_note_button_changed ()
994         {
995                 Keyboard::set_insert_note_button (_insert_note_button_spin.get_value_as_int());
996         }
997
998         ComboBoxText _keyboard_layout_selector;
999         ComboBoxText _edit_modifier_combo;
1000         ComboBoxText _delete_modifier_combo;
1001         ComboBoxText _copy_modifier_combo;
1002         ComboBoxText _insert_note_modifier_combo;
1003         ComboBoxText _snap_modifier_combo;
1004         ComboBoxText _snap_delta_combo;
1005         ComboBoxText _constraint_modifier_combo;
1006         ComboBoxText _trim_contents_combo;
1007         ComboBoxText _trim_overlap_combo;
1008         ComboBoxText _trim_anchored_combo;
1009         ComboBoxText _trim_jump_combo;
1010         ComboBoxText _fine_adjust_combo;
1011         ComboBoxText _push_points_combo;
1012         ComboBoxText _note_size_relative_combo;
1013         Adjustment _delete_button_adjustment;
1014         SpinButton _delete_button_spin;
1015         Adjustment _edit_button_adjustment;
1016         SpinButton _edit_button_spin;
1017         Adjustment _insert_note_button_adjustment;
1018         SpinButton _insert_note_button_spin;
1019
1020 };
1021
1022 class FontScalingOptions : public OptionEditorBox
1023 {
1024 public:
1025         FontScalingOptions () :
1026                 _dpi_adjustment (100, 50, 250, 1, 5),
1027                 _dpi_slider (_dpi_adjustment)
1028         {
1029                 _dpi_adjustment.set_value (UIConfiguration::instance().get_font_scale() / 1024.);
1030
1031                 Label* l = manage (new Label (_("GUI and Font scaling:")));
1032                 l->set_name ("OptionsLabel");
1033
1034                 const std::string dflt = _("Default");
1035                 const std::string empty = X_(""); // despite gtk-doc saying so, NULL does not work as reference
1036
1037                 _dpi_slider.set_name("FontScaleSlider");
1038                 _dpi_slider.set_update_policy (UPDATE_DISCONTINUOUS);
1039                 _dpi_slider.set_draw_value(false);
1040                 _dpi_slider.add_mark(50,  Gtk::POS_TOP, empty);
1041                 _dpi_slider.add_mark(60,  Gtk::POS_TOP, empty);
1042                 _dpi_slider.add_mark(70,  Gtk::POS_TOP, empty);
1043                 _dpi_slider.add_mark(80,  Gtk::POS_TOP, empty);
1044                 _dpi_slider.add_mark(90,  Gtk::POS_TOP, empty);
1045                 _dpi_slider.add_mark(100, Gtk::POS_TOP, dflt);
1046                 _dpi_slider.add_mark(125, Gtk::POS_TOP, empty);
1047                 _dpi_slider.add_mark(150, Gtk::POS_TOP, empty);
1048                 _dpi_slider.add_mark(175, Gtk::POS_TOP, empty);
1049                 _dpi_slider.add_mark(200, Gtk::POS_TOP, empty);
1050                 _dpi_slider.add_mark(225, Gtk::POS_TOP, empty);
1051                 _dpi_slider.add_mark(250, Gtk::POS_TOP, empty);
1052
1053                 HBox* h = manage (new HBox);
1054                 h->set_spacing (4);
1055                 h->pack_start (*l, false, false);
1056                 h->pack_start (_dpi_slider, true, true);
1057
1058                 _box->pack_start (*h, false, false);
1059
1060                 set_note (_("Adjusting the scale requires an application restart to re-layout."));
1061
1062                 _dpi_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &FontScalingOptions::dpi_changed));
1063         }
1064
1065         void parameter_changed (string const & p)
1066         {
1067                 if (p == "font-scale") {
1068                         _dpi_adjustment.set_value (UIConfiguration::instance().get_font_scale() / 1024.);
1069                 }
1070         }
1071
1072         void set_state_from_config ()
1073         {
1074                 parameter_changed ("font-scale");
1075         }
1076
1077 private:
1078
1079         void dpi_changed ()
1080         {
1081                 UIConfiguration::instance().set_font_scale ((long) floor (_dpi_adjustment.get_value() * 1024.));
1082                 /* XXX: should be triggered from the parameter changed signal */
1083                 UIConfiguration::instance().reset_dpi ();
1084         }
1085
1086         Adjustment _dpi_adjustment;
1087         HScale _dpi_slider;
1088 };
1089
1090 class VstTimeOutSliderOption : public OptionEditorBox
1091 {
1092 public:
1093         VstTimeOutSliderOption (RCConfiguration* c)
1094                 : _rc_config (c)
1095                 , _timeout_adjustment (0, 0, 3000, 50, 50)
1096                 , _timeout_slider (_timeout_adjustment)
1097         {
1098                 _timeout_slider.set_digits (0);
1099                 _timeout_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &VstTimeOutSliderOption::timeout_changed));
1100
1101                 _timeout_slider.set_draw_value(false);
1102                 _timeout_slider.add_mark(   0,  Gtk::POS_TOP, _("\u221e")); // infinity
1103                 _timeout_slider.add_mark( 300,  Gtk::POS_TOP, _("30 sec"));
1104                 _timeout_slider.add_mark( 600,  Gtk::POS_TOP, _("1 min"));
1105                 _timeout_slider.add_mark(1200,  Gtk::POS_TOP, _("2 mins"));
1106                 _timeout_slider.add_mark(1800,  Gtk::POS_TOP, _("3 mins"));
1107                 _timeout_slider.add_mark(2400,  Gtk::POS_TOP, _("4 mins"));
1108                 _timeout_slider.add_mark(3000,  Gtk::POS_TOP, _("5 mins"));
1109
1110                 Gtkmm2ext::UI::instance()->set_tip(_timeout_slider,
1111                          _("Specify the default timeout for plugin instantiation. Plugins that require more time to load will be blacklisted. A value of 0 disables the timeout."));
1112
1113                 Label* l = manage (left_aligned_label (_("Scan Time Out:")));
1114                 HBox* h = manage (new HBox);
1115                 h->set_spacing (4);
1116                 h->pack_start (*l, false, false);
1117                 h->pack_start (_timeout_slider, true, true);
1118
1119                 _box->pack_start (*h, false, false);
1120         }
1121
1122         void parameter_changed (string const & p)
1123         {
1124                 if (p == "vst-scan-timeout") {
1125                         int const x = _rc_config->get_vst_scan_timeout();
1126                         _timeout_adjustment.set_value (x);
1127                 }
1128         }
1129
1130         void set_state_from_config ()
1131         {
1132                 parameter_changed ("vst-scan-timeout");
1133         }
1134
1135 private:
1136
1137         void timeout_changed ()
1138         {
1139                 int x = floor(_timeout_adjustment.get_value());
1140                 _rc_config->set_vst_scan_timeout(x);
1141         }
1142
1143         RCConfiguration* _rc_config;
1144         Adjustment _timeout_adjustment;
1145         HScale _timeout_slider;
1146 };
1147
1148
1149
1150
1151
1152 class ClipLevelOptions : public OptionEditorBox
1153 {
1154 public:
1155         ClipLevelOptions ()
1156                 : _clip_level_adjustment (-.5, -50.0, 0.0, 0.1, 1.0) /* units of dB */
1157                 , _clip_level_slider (_clip_level_adjustment)
1158         {
1159                 _clip_level_adjustment.set_value (UIConfiguration::instance().get_waveform_clip_level ());
1160
1161                 Label* l = manage (new Label (_("Waveform Clip Level (dBFS):")));
1162                 l->set_name ("OptionsLabel");
1163
1164                 _clip_level_slider.set_update_policy (UPDATE_DISCONTINUOUS);
1165                 HBox* h = manage (new HBox);
1166                 h->set_spacing (4);
1167                 h->pack_start (*l, false, false);
1168                 h->pack_start (_clip_level_slider, true, true);
1169
1170                 _box->pack_start (*h, false, false);
1171
1172                 _clip_level_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &ClipLevelOptions::clip_level_changed));
1173         }
1174
1175         void parameter_changed (string const & p)
1176         {
1177                 if (p == "waveform-clip-level") {
1178                         _clip_level_adjustment.set_value (UIConfiguration::instance().get_waveform_clip_level());
1179                 }
1180         }
1181
1182         void set_state_from_config ()
1183         {
1184                 parameter_changed ("waveform-clip-level");
1185         }
1186
1187 private:
1188
1189         void clip_level_changed ()
1190         {
1191                 UIConfiguration::instance().set_waveform_clip_level (_clip_level_adjustment.get_value());
1192                 /* XXX: should be triggered from the parameter changed signal */
1193                 ArdourCanvas::WaveView::set_clip_level (_clip_level_adjustment.get_value());
1194         }
1195
1196         Adjustment _clip_level_adjustment;
1197         HScale _clip_level_slider;
1198 };
1199
1200 class BufferingOptions : public OptionEditorBox
1201 {
1202 public:
1203         BufferingOptions (RCConfiguration* c)
1204                 : _rc_config (c)
1205                 , _playback_adjustment (5, 1, 60, 1, 4)
1206                 , _capture_adjustment (5, 1, 60, 1, 4)
1207                 , _playback_slider (_playback_adjustment)
1208                 , _capture_slider (_capture_adjustment)
1209         {
1210                 vector<string> presets;
1211
1212                 /* these must match the order of the enums for BufferingPreset */
1213
1214                 presets.push_back (_("Small sessions (4-16 tracks)"));
1215                 presets.push_back (_("Medium sessions (16-64 tracks)"));
1216                 presets.push_back (_("Large sessions (64+ tracks)"));
1217                 presets.push_back (_("Custom (set by sliders below)"));
1218
1219                 set_popdown_strings (_buffering_presets_combo, presets);
1220
1221                 Label* l = manage (new Label (_("Preset:")));
1222                 l->set_name ("OptionsLabel");
1223                 HBox* h = manage (new HBox);
1224                 h->set_spacing (12);
1225                 h->pack_start (*l, false, false);
1226                 h->pack_start (_buffering_presets_combo, true, true);
1227                 _box->pack_start (*h, false, false);
1228
1229                 _buffering_presets_combo.signal_changed().connect (sigc::mem_fun (*this, &BufferingOptions::preset_changed));
1230
1231                 _playback_adjustment.set_value (_rc_config->get_audio_playback_buffer_seconds());
1232
1233                 l = manage (new Label (_("Playback (seconds of buffering):")));
1234                 l->set_name ("OptionsLabel");
1235
1236                 _playback_slider.set_update_policy (UPDATE_DISCONTINUOUS);
1237                 h = manage (new HBox);
1238                 h->set_spacing (4);
1239                 h->pack_start (*l, false, false);
1240                 h->pack_start (_playback_slider, true, true);
1241
1242                 _box->pack_start (*h, false, false);
1243
1244                 _capture_adjustment.set_value (_rc_config->get_audio_capture_buffer_seconds());
1245
1246                 l = manage (new Label (_("Recording (seconds of buffering):")));
1247                 l->set_name ("OptionsLabel");
1248
1249                 _capture_slider.set_update_policy (UPDATE_DISCONTINUOUS);
1250                 h = manage (new HBox);
1251                 h->set_spacing (4);
1252                 h->pack_start (*l, false, false);
1253                 h->pack_start (_capture_slider, true, true);
1254
1255                 _box->pack_start (*h, false, false);
1256
1257                 _capture_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &BufferingOptions::capture_changed));
1258                 _playback_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &BufferingOptions::playback_changed));
1259         }
1260
1261         void parameter_changed (string const & p)
1262         {
1263                 if (p == "buffering-preset") {
1264                         switch (_rc_config->get_buffering_preset()) {
1265                         case Small:
1266                                 _playback_slider.set_sensitive (false);
1267                                 _capture_slider.set_sensitive (false);
1268                                 _buffering_presets_combo.set_active (0);
1269                                 break;
1270                         case Medium:
1271                                 _playback_slider.set_sensitive (false);
1272                                 _capture_slider.set_sensitive (false);
1273                                 _buffering_presets_combo.set_active (1);
1274                                 break;
1275                         case Large:
1276                                 _playback_slider.set_sensitive (false);
1277                                 _capture_slider.set_sensitive (false);
1278                                 _buffering_presets_combo.set_active (2);
1279                                 break;
1280                         case Custom:
1281                                 _playback_slider.set_sensitive (true);
1282                                 _capture_slider.set_sensitive (true);
1283                                 _buffering_presets_combo.set_active (3);
1284                                 break;
1285                         }
1286                 }
1287
1288                 if (p == "playback-buffer-seconds") {
1289                         _playback_adjustment.set_value (_rc_config->get_audio_playback_buffer_seconds());
1290                 } else if (p == "capture-buffer-seconds") {
1291                         _capture_adjustment.set_value (_rc_config->get_audio_capture_buffer_seconds());
1292                 }
1293         }
1294
1295         void set_state_from_config ()
1296         {
1297                 parameter_changed ("buffering-preset");
1298                 parameter_changed ("playback-buffer-seconds");
1299                 parameter_changed ("capture-buffer-seconds");
1300         }
1301
1302 private:
1303
1304         void preset_changed ()
1305         {
1306                 int index = _buffering_presets_combo.get_active_row_number ();
1307                 if (index < 0) {
1308                         return;
1309                 }
1310                 switch (index) {
1311                 case 0:
1312                         _rc_config->set_buffering_preset (Small);
1313                         break;
1314                 case 1:
1315                         _rc_config->set_buffering_preset (Medium);
1316                         break;
1317                 case 2:
1318                         _rc_config->set_buffering_preset (Large);
1319                         break;
1320                 case 3:
1321                         _rc_config->set_buffering_preset (Custom);
1322                         break;
1323                 default:
1324                         error << string_compose (_("programming error: unknown buffering preset string, index = %1"), index) << endmsg;
1325                         break;
1326                 }
1327         }
1328
1329         void playback_changed ()
1330         {
1331                 _rc_config->set_audio_playback_buffer_seconds ((long) _playback_adjustment.get_value());
1332         }
1333
1334         void capture_changed ()
1335         {
1336                 _rc_config->set_audio_capture_buffer_seconds ((long) _capture_adjustment.get_value());
1337         }
1338
1339         RCConfiguration* _rc_config;
1340         Adjustment _playback_adjustment;
1341         Adjustment _capture_adjustment;
1342         HScale _playback_slider;
1343         HScale _capture_slider;
1344         ComboBoxText _buffering_presets_combo;
1345 };
1346
1347 class ControlSurfacesOptions : public OptionEditorBox
1348 {
1349 public:
1350         ControlSurfacesOptions ()
1351                 : _ignore_view_change (0)
1352         {
1353                 _store = ListStore::create (_model);
1354                 _view.set_model (_store);
1355                 _view.append_column (_("Control Surface Protocol"), _model.name);
1356                 _view.get_column(0)->set_resizable (true);
1357                 _view.get_column(0)->set_expand (true);
1358                 _view.append_column_editable (_("Enabled"), _model.enabled);
1359                 _view.append_column_editable (_("Feedback"), _model.feedback);
1360
1361                 _box->pack_start (_view, false, false);
1362
1363                 Gtk::HBox* edit_box = manage (new Gtk::HBox);
1364                 edit_box->set_spacing(3);
1365                 _box->pack_start (*edit_box, false, false);
1366                 edit_box->show ();
1367
1368                 Label* label = manage (new Label);
1369                 label->set_text (_("Click to edit the settings for selected protocol ( it must be ENABLED first ):"));
1370                 edit_box->pack_start (*label, false, false);
1371                 label->show ();
1372
1373                 edit_button = manage (new Button(_("Show Protocol Settings")));
1374                 edit_button->signal_clicked().connect (sigc::mem_fun(*this, &ControlSurfacesOptions::edit_btn_clicked));
1375                 edit_box->pack_start (*edit_button, true, true);
1376                 edit_button->set_sensitive (false);
1377                 edit_button->show ();
1378
1379                 ControlProtocolManager& m = ControlProtocolManager::instance ();
1380                 m.ProtocolStatusChange.connect (protocol_status_connection, MISSING_INVALIDATOR,
1381                                                 boost::bind (&ControlSurfacesOptions::protocol_status_changed, this, _1), gui_context());
1382
1383                 _store->signal_row_changed().connect (sigc::mem_fun (*this, &ControlSurfacesOptions::view_changed));
1384                 _view.signal_button_press_event().connect_notify (sigc::mem_fun(*this, &ControlSurfacesOptions::edit_clicked));
1385                 _view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &ControlSurfacesOptions::selection_changed));
1386         }
1387
1388         void parameter_changed (std::string const &)
1389         {
1390
1391         }
1392
1393         void set_state_from_config ()
1394         {
1395                 _store->clear ();
1396
1397                 ControlProtocolManager& m = ControlProtocolManager::instance ();
1398                 for (list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
1399
1400                         if (!(*i)->mandatory) {
1401                                 TreeModel::Row r = *_store->append ();
1402                                 r[_model.name] = (*i)->name;
1403                                 r[_model.enabled] = ((*i)->protocol || (*i)->requested);
1404                                 r[_model.feedback] = ((*i)->protocol && (*i)->protocol->get_feedback ());
1405                                 r[_model.protocol_info] = *i;
1406                         }
1407                 }
1408         }
1409
1410 private:
1411
1412         void protocol_status_changed (ControlProtocolInfo* cpi) {
1413                 /* find the row */
1414                 TreeModel::Children rows = _store->children();
1415
1416                 for (TreeModel::Children::iterator x = rows.begin(); x != rows.end(); ++x) {
1417                         string n = ((*x)[_model.name]);
1418
1419                         if ((*x)[_model.protocol_info] == cpi) {
1420                                 _ignore_view_change++;
1421                                 (*x)[_model.enabled] = (cpi->protocol || cpi->requested);
1422                                 _ignore_view_change--;
1423                                 break;
1424                         }
1425                 }
1426         }
1427
1428         void selection_changed ()
1429         {
1430                 //enable the Edit button when a row is selected for editing
1431                 TreeModel::Row row = *(_view.get_selection()->get_selected());
1432                 if (row && row[_model.enabled])
1433                         edit_button->set_sensitive (true);
1434                 else
1435                         edit_button->set_sensitive (false);
1436         }
1437
1438         void view_changed (TreeModel::Path const &, TreeModel::iterator const & i)
1439         {
1440                 TreeModel::Row r = *i;
1441
1442                 if (_ignore_view_change) {
1443                         return;
1444                 }
1445
1446                 ControlProtocolInfo* cpi = r[_model.protocol_info];
1447                 if (!cpi) {
1448                         return;
1449                 }
1450
1451                 bool const was_enabled = (cpi->protocol != 0);
1452                 bool const is_enabled = r[_model.enabled];
1453
1454
1455                 if (was_enabled != is_enabled) {
1456
1457                         if (!was_enabled) {
1458                                 ControlProtocolManager::instance().activate (*cpi);
1459                         } else {
1460                                 ControlProtocolManager::instance().deactivate (*cpi);
1461                         }
1462                 }
1463
1464                 bool const was_feedback = (cpi->protocol && cpi->protocol->get_feedback ());
1465                 bool const is_feedback = r[_model.feedback];
1466
1467                 if (was_feedback != is_feedback && cpi->protocol) {
1468                         cpi->protocol->set_feedback (is_feedback);
1469                 }
1470         }
1471
1472         void edit_btn_clicked ()
1473         {
1474                 std::string name;
1475                 ControlProtocolInfo* cpi;
1476                 TreeModel::Row row;
1477
1478                 row = *(_view.get_selection()->get_selected());
1479                 if (!row[_model.enabled]) {
1480                         return;
1481                 }
1482                 cpi = row[_model.protocol_info];
1483                 if (!cpi || !cpi->protocol || !cpi->protocol->has_editor ()) {
1484                         return;
1485                 }
1486                 Box* box = (Box*) cpi->protocol->get_gui ();
1487                 if (!box) {
1488                         return;
1489                 }
1490                 if (box->get_parent()) {
1491                         static_cast<ArdourWindow*>(box->get_parent())->present();
1492                         return;
1493                 }
1494                 WindowTitle title (Glib::get_application_name());
1495                 title += row[_model.name];
1496                 title += _("Configuration");
1497                 /* once created, the window is managed by the surface itself (as ->get_parent())
1498                  * Surface's tear_down_gui() is called on session close, when de-activating
1499                  * or re-initializing a surface.
1500                  * tear_down_gui() hides an deletes the Window if it exists.
1501                  */
1502                 ArdourWindow* win = new ArdourWindow (*((Gtk::Window*) _view.get_toplevel()), title.get_string());
1503                 win->set_title ("Control Protocol Options");
1504                 win->add (*box);
1505                 box->show ();
1506                 win->present ();
1507         }
1508
1509         void edit_clicked (GdkEventButton* ev)
1510         {
1511                 if (ev->type != GDK_2BUTTON_PRESS) {
1512                         return;
1513                 }
1514
1515                 edit_btn_clicked();
1516         }
1517
1518         class ControlSurfacesModelColumns : public TreeModelColumnRecord
1519         {
1520         public:
1521
1522                 ControlSurfacesModelColumns ()
1523                 {
1524                         add (name);
1525                         add (enabled);
1526                         add (feedback);
1527                         add (protocol_info);
1528                 }
1529
1530                 TreeModelColumn<string> name;
1531                 TreeModelColumn<bool> enabled;
1532                 TreeModelColumn<bool> feedback;
1533                 TreeModelColumn<ControlProtocolInfo*> protocol_info;
1534         };
1535
1536         Glib::RefPtr<ListStore> _store;
1537         ControlSurfacesModelColumns _model;
1538         TreeView _view;
1539         PBD::ScopedConnection protocol_status_connection;
1540         uint32_t _ignore_view_change;
1541         Gtk::Button* edit_button;
1542 };
1543
1544 class VideoTimelineOptions : public OptionEditorBox
1545 {
1546 public:
1547         VideoTimelineOptions (RCConfiguration* c)
1548                 : _rc_config (c)
1549                 , _show_video_export_info_button (_("Show Video Export Info before export"))
1550                 , _show_video_server_dialog_button (_("Show Video Server Startup Dialog"))
1551                 , _video_advanced_setup_button (_("Advanced Setup (remote video server)"))
1552                 , _xjadeo_browse_button (_("Browse..."))
1553         {
1554                 Table* t = manage (new Table (8, 4));
1555                 t->set_spacings (4);
1556
1557                 std::stringstream s;
1558                 s << "<b>" << _("Video Server") << "</b>";
1559                 Label* l = manage (new Label (s.str()));
1560                 l->set_use_markup (true);
1561                 l->set_alignment (0, 0.5);
1562                 t->attach (*l, 0, 4, 0, 1, EXPAND | FILL, FILL | EXPAND, 0, 8);
1563
1564                 t->attach (_video_advanced_setup_button, 1, 4, 1, 2);
1565                 _video_advanced_setup_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::video_advanced_setup_toggled));
1566                 Gtkmm2ext::UI::instance()->set_tip (_video_advanced_setup_button,
1567                                             _("<b>When enabled</b> you can speficify a custom video-server URL and docroot. - Do not enable this option unless you know what you are doing."));
1568
1569                 l = manage (new Label (_("Video Server URL:")));
1570                 l->set_alignment (0, 0.5);
1571                 t->attach (*l, 1, 2, 2, 3, FILL);
1572                 t->attach (_video_server_url_entry, 2, 4, 2, 3, FILL);
1573                 Gtkmm2ext::UI::instance()->set_tip (_video_server_url_entry,
1574                                             _("Base URL of the video-server including http prefix. This is usually 'http://hostname.example.org:1554/' and defaults to 'http://localhost:1554/' when the video-server is running locally"));
1575
1576                 l = manage (new Label (_("Video Folder:")));
1577                 l->set_alignment (0, 0.5);
1578                 t->attach (*l, 1, 2, 3, 4, FILL);
1579                 t->attach (_video_server_docroot_entry, 2, 4, 3, 4);
1580                 Gtkmm2ext::UI::instance()->set_tip (_video_server_docroot_entry,
1581                                             _("Local path to the video-server document-root. Only files below this directory will be accessible by the video-server. If the server run on a remote host, it should point to a network mounted folder of the server's docroot or be left empty if it is unvailable. It is used for the local video-monitor and file-browsing when opening/adding a video file."));
1582
1583                 t->attach (_show_video_export_info_button, 1, 4, 4, 5);
1584                 _show_video_export_info_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::show_video_export_info_toggled));
1585                 Gtkmm2ext::UI::instance()->set_tip (_show_video_export_info_button,
1586                                             _("<b>When enabled</b> an information window with details is displayed before the video-export dialog."));
1587
1588                 t->attach (_show_video_server_dialog_button, 1, 4, 5, 6);
1589                 _show_video_server_dialog_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::show_video_server_dialog_toggled));
1590                 Gtkmm2ext::UI::instance()->set_tip (_show_video_server_dialog_button,
1591                                             _("<b>When enabled</b> the video server is never launched automatically without confirmation"));
1592
1593                 s.str (std::string ());
1594                 s << "<b>" << _("Video Monitor") << "</b>";
1595                 l = manage (new Label (s.str()));
1596                 l->set_use_markup (true);
1597                 l->set_alignment (0, 0.5);
1598                 t->attach (*l, 0, 4, 6, 7, EXPAND | FILL, FILL | EXPAND, 0, 8);
1599
1600                 l = manage (new Label (string_compose (_("Custom Path to Video Monitor (%1) - leave empty for default:"),
1601 #ifdef __APPLE__
1602                                                 "Jadeo.app"
1603 #elif defined PLATFORM_WINDOWS
1604                                                 "xjadeo.exe"
1605 #else
1606                                                 "xjadeo"
1607 #endif
1608                                                 )));
1609                 l->set_alignment (0, 0.5);
1610                 t->attach (*l, 1, 4, 7, 8, FILL);
1611                 t->attach (_custom_xjadeo_path, 2, 3, 8, 9);
1612                 Gtkmm2ext::UI::instance()->set_tip (_custom_xjadeo_path, _("Set a custom path to the Video Monitor Executable, changing this requires a restart."));
1613                 t->attach (_xjadeo_browse_button, 3, 4, 8, 9, FILL);
1614
1615                 _video_server_url_entry.signal_changed().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_url_changed));
1616                 _video_server_url_entry.signal_activate().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_url_changed));
1617                 _video_server_docroot_entry.signal_changed().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_docroot_changed));
1618                 _video_server_docroot_entry.signal_activate().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_docroot_changed));
1619                 _custom_xjadeo_path.signal_changed().connect (sigc::mem_fun (*this, &VideoTimelineOptions::custom_xjadeo_path_changed));
1620                 _xjadeo_browse_button.signal_clicked ().connect (sigc::mem_fun (*this, &VideoTimelineOptions::xjadeo_browse_clicked));
1621
1622                 // xjadeo-path is a UIConfig parameter
1623                 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &VideoTimelineOptions::parameter_changed));
1624
1625                 _box->pack_start (*t,true,true);
1626         }
1627
1628         void server_url_changed ()
1629         {
1630                 _rc_config->set_video_server_url (_video_server_url_entry.get_text());
1631         }
1632
1633         void server_docroot_changed ()
1634         {
1635                 _rc_config->set_video_server_docroot (_video_server_docroot_entry.get_text());
1636         }
1637
1638         void show_video_export_info_toggled ()
1639         {
1640                 bool const x = _show_video_export_info_button.get_active ();
1641                 _rc_config->set_show_video_export_info (x);
1642         }
1643
1644         void show_video_server_dialog_toggled ()
1645         {
1646                 bool const x = _show_video_server_dialog_button.get_active ();
1647                 _rc_config->set_show_video_server_dialog (x);
1648         }
1649
1650         void video_advanced_setup_toggled ()
1651         {
1652                 bool const x = _video_advanced_setup_button.get_active ();
1653                 _rc_config->set_video_advanced_setup(x);
1654         }
1655
1656         void custom_xjadeo_path_changed ()
1657         {
1658                 UIConfiguration::instance().set_xjadeo_binary (_custom_xjadeo_path.get_text());
1659         }
1660
1661         void xjadeo_browse_clicked ()
1662         {
1663                 Gtk::FileChooserDialog dialog(_("Set Video Monitor Executable"), Gtk::FILE_CHOOSER_ACTION_OPEN);
1664                 dialog.set_filename (UIConfiguration::instance().get_xjadeo_binary());
1665                 dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1666                 dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
1667                 if (dialog.run () == Gtk::RESPONSE_OK) {
1668                         const std::string& filename = dialog.get_filename();
1669                         if (!filename.empty() && (
1670 #ifdef __APPLE__
1671                                         Glib::file_test (filename + "/Contents/MacOS/xjadeo", Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE) ||
1672 #endif
1673                                         Glib::file_test (filename, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)
1674                                         )) {
1675                                 UIConfiguration::instance().set_xjadeo_binary (filename);
1676                         }
1677                 }
1678         }
1679
1680         void parameter_changed (string const & p)
1681         {
1682                 if (p == "video-server-url") {
1683                         _video_server_url_entry.set_text (_rc_config->get_video_server_url());
1684                 } else if (p == "video-server-docroot") {
1685                         _video_server_docroot_entry.set_text (_rc_config->get_video_server_docroot());
1686                 } else if (p == "show-video-export-info") {
1687                         bool const x = _rc_config->get_show_video_export_info();
1688                         _show_video_export_info_button.set_active (x);
1689                 } else if (p == "show-video-server-dialog") {
1690                         bool const x = _rc_config->get_show_video_server_dialog();
1691                         _show_video_server_dialog_button.set_active (x);
1692                 } else if (p == "video-advanced-setup") {
1693                         bool const x = _rc_config->get_video_advanced_setup();
1694                         _video_advanced_setup_button.set_active(x);
1695                         _video_server_docroot_entry.set_sensitive(x);
1696                         _video_server_url_entry.set_sensitive(x);
1697                 } else if (p == "xjadeo-binary") {
1698                         _custom_xjadeo_path.set_text (UIConfiguration::instance().get_xjadeo_binary());
1699                 }
1700         }
1701
1702         void set_state_from_config ()
1703         {
1704                 parameter_changed ("video-server-url");
1705                 parameter_changed ("video-server-docroot");
1706                 parameter_changed ("video-monitor-setup-dialog");
1707                 parameter_changed ("show-video-export-info");
1708                 parameter_changed ("show-video-server-dialog");
1709                 parameter_changed ("video-advanced-setup");
1710                 parameter_changed ("xjadeo-binary");
1711         }
1712
1713 private:
1714         RCConfiguration* _rc_config;
1715         Entry _video_server_url_entry;
1716         Entry _video_server_docroot_entry;
1717         Entry _custom_xjadeo_path;
1718         CheckButton _show_video_export_info_button;
1719         CheckButton _show_video_server_dialog_button;
1720         CheckButton _video_advanced_setup_button;
1721         Button _xjadeo_browse_button;
1722 };
1723
1724 class ColumVisibilityOption : public Option
1725 {
1726         public:
1727         ColumVisibilityOption (string id, string name, uint32_t n_col, sigc::slot<uint32_t> get, sigc::slot<bool, uint32_t> set)
1728                 : Option (id, name)
1729                 , _heading (name)
1730                 , _n_col (n_col)
1731                 , _get (get)
1732                 , _set (set)
1733         {
1734                 cb = (CheckButton**) malloc (sizeof (CheckButton*) * n_col);
1735                 for (uint32_t i = 0; i < n_col; ++i) {
1736                         CheckButton* col = manage (new CheckButton (string_compose (_("Column %1"), i + 1)));
1737                         col->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &ColumVisibilityOption::column_toggled), i));
1738                         _hbox.pack_start (*col);
1739                         cb[i] = col;
1740                 }
1741                 parameter_changed (id);
1742         }
1743
1744         ~ColumVisibilityOption () {
1745                 free (cb);
1746         }
1747
1748         Gtk::Widget& tip_widget() { return _hbox; }
1749
1750         void set_state_from_config ()
1751         {
1752                 uint32_t c = _get();
1753                 for (uint32_t i = 0; i < _n_col; ++i) {
1754                         bool en = (c & (1<<i)) ? true : false;
1755                         if (cb[i]->get_active () != en) {
1756                                 cb[i]->set_active (en);
1757                         }
1758                 }
1759         }
1760
1761         void add_to_page (OptionEditorPage* p)
1762         {
1763                 _heading.add_to_page (p);
1764                 add_widget_to_page (p, &_hbox);
1765         }
1766         private:
1767
1768         void column_toggled (int b) {
1769                 uint32_t c = _get();
1770                 uint32_t cc = c;
1771                 if (cb[b]->get_active ()) {
1772                         c |= (1<<b);
1773                 } else {
1774                         c &= ~(1<<b);
1775                 }
1776                 if (cc != c) {
1777                         _set (c);
1778                 }
1779         }
1780
1781         HBox _hbox;
1782         OptionEditorHeading _heading;
1783
1784         CheckButton** cb;
1785         uint32_t _n_col;
1786         sigc::slot<uint32_t> _get;
1787         sigc::slot<bool, uint32_t> _set;
1788 };
1789
1790
1791 /** A class which allows control of visibility of some editor components usign
1792  *  a VisibilityGroup.  The caller should pass in a `dummy' VisibilityGroup
1793  *  which has the correct members, but with null widget pointers.  This
1794  *  class allows the user to set visibility of the members, the details
1795  *  of which are stored in a configuration variable which can be watched
1796  *  by parts of the editor that actually contain the widgets whose visibility
1797  *  is being controlled.
1798  */
1799
1800 class VisibilityOption : public Option
1801 {
1802 public:
1803         /** @param name User-visible name for this group.
1804          *  @param g `Dummy' VisibilityGroup (as described above).
1805          *  @param get Method to get the value of the appropriate configuration variable.
1806          *  @param set Method to set the value of the appropriate configuration variable.
1807          */
1808         VisibilityOption (string name, VisibilityGroup* g, sigc::slot<string> get, sigc::slot<bool, string> set)
1809                 : Option (g->get_state_name(), name)
1810                 , _heading (name)
1811                 , _visibility_group (g)
1812                 , _get (get)
1813                 , _set (set)
1814         {
1815                 /* Watch for changes made by the user to our members */
1816                 _visibility_group->VisibilityChanged.connect_same_thread (
1817                         _visibility_group_connection, sigc::bind (&VisibilityOption::changed, this)
1818                         );
1819         }
1820
1821         void set_state_from_config ()
1822         {
1823                 /* Set our state from the current configuration */
1824                 _visibility_group->set_state (_get ());
1825         }
1826
1827         void add_to_page (OptionEditorPage* p)
1828         {
1829                 _heading.add_to_page (p);
1830                 add_widget_to_page (p, _visibility_group->list_view ());
1831         }
1832
1833         Gtk::Widget& tip_widget() { return *_visibility_group->list_view (); }
1834
1835 private:
1836         void changed ()
1837         {
1838                 /* The user has changed something, so reflect this change
1839                    in the RCConfiguration.
1840                 */
1841                 _set (_visibility_group->get_state_value ());
1842         }
1843
1844         OptionEditorHeading _heading;
1845         VisibilityGroup* _visibility_group;
1846         sigc::slot<std::string> _get;
1847         sigc::slot<bool, std::string> _set;
1848         PBD::ScopedConnection _visibility_group_connection;
1849 };
1850
1851
1852
1853 RCOptionEditor::RCOptionEditor ()
1854         : OptionEditorContainer (Config, string_compose (_("%1 Preferences"), PROGRAM_NAME))
1855         , Tabbable (*this, _("Preferences")) /* pack self-as-vbox into tabbable */
1856         , _rc_config (Config)
1857         , _mixer_strip_visibility ("mixer-element-visibility")
1858 {
1859         XMLNode* node = ARDOUR_UI::instance()->preferences_settings();
1860         if (node) {
1861                 /* gcc4 complains about ambiguity with Gtk::Widget::set_state
1862                    (Gtk::StateType) here !!!
1863                 */
1864                 Tabbable::set_state (*node, Stateful::loading_state_version);
1865         }
1866
1867         UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &RCOptionEditor::parameter_changed));
1868
1869         /* MISC */
1870
1871         uint32_t hwcpus = hardware_concurrency ();
1872         BoolOption* bo;
1873         BoolComboOption* bco;
1874
1875         if (hwcpus > 1) {
1876                 add_option (_("Misc"), new OptionEditorHeading (_("DSP CPU Utilization")));
1877
1878                 ComboOption<int32_t>* procs = new ComboOption<int32_t> (
1879                         "processor-usage",
1880                         _("Signal processing uses"),
1881                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_processor_usage),
1882                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_processor_usage)
1883                         );
1884
1885                 procs->add (-1, _("all but one processor"));
1886                 procs->add (0, _("all available processors"));
1887
1888                 for (uint32_t i = 1; i <= hwcpus; ++i) {
1889                         procs->add (i, string_compose (_("%1 processors"), i));
1890                 }
1891
1892                 procs->set_note (string_compose (_("This setting will only take effect when %1 is restarted."), PROGRAM_NAME));
1893
1894                 add_option (_("Misc"), procs);
1895         }
1896
1897         add_option (_("Misc"), new OptionEditorHeading (S_("Options|Undo")));
1898
1899         add_option (_("Misc"), new UndoOptions (_rc_config));
1900
1901         add_option (_("Misc"),
1902              new BoolOption (
1903                      "verify-remove-last-capture",
1904                      _("Verify removal of last capture"),
1905                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_verify_remove_last_capture),
1906                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_verify_remove_last_capture)
1907                      ));
1908
1909         add_option (_("Misc"), new OptionEditorHeading (_("Session Management")));
1910
1911         add_option (_("Misc"),
1912              new BoolOption (
1913                      "periodic-safety-backups",
1914                      _("Make periodic backups of the session file"),
1915                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_periodic_safety_backups),
1916                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_periodic_safety_backups)
1917                      ));
1918
1919         add_option (_("Misc"),
1920              new BoolOption (
1921                      "only-copy-imported-files",
1922                      _("Always copy imported files"),
1923                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_only_copy_imported_files),
1924                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_only_copy_imported_files)
1925                      ));
1926
1927         add_option (_("Misc"), new DirectoryOption (
1928                             X_("default-session-parent-dir"),
1929                             _("Default folder for new sessions:"),
1930                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_default_session_parent_dir),
1931                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_default_session_parent_dir)
1932                             ));
1933
1934         add_option (_("Misc"),
1935              new SpinOption<uint32_t> (
1936                      "max-recent-sessions",
1937                      _("Maximum number of recent sessions"),
1938                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_max_recent_sessions),
1939                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_max_recent_sessions),
1940                      0, 1000, 1, 20
1941                      ));
1942
1943         add_option (_("Misc/Click"), new OptionEditorHeading (_("Click")));
1944
1945         add_option (_("Misc/Click"), new ClickOptions (_rc_config));
1946
1947         add_option (_("Misc/Click"),
1948              new FaderOption (
1949                      "click-gain",
1950                      _("Click gain level"),
1951                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_click_gain),
1952                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_click_gain)
1953                      ));
1954
1955         add_option (_("Misc"), new OptionEditorHeading (_("Automation")));
1956
1957         add_option (_("Misc"),
1958              new SpinOption<double> (
1959                      "automation-thinning-factor",
1960                      _("Thinning factor (larger value => less data)"),
1961                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_thinning_factor),
1962                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_thinning_factor),
1963                      0, 1000, 1, 20
1964                      ));
1965
1966         add_option (_("Misc"),
1967              new SpinOption<double> (
1968                      "automation-interval-msecs",
1969                      _("Automation sampling interval (milliseconds)"),
1970                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_interval_msecs),
1971                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_interval_msecs),
1972                      1, 1000, 1, 20
1973                      ));
1974
1975         /* TRANSPORT */
1976
1977         add_option (_("Transport"), new OptionEditorHeading (S_("Transport Options")));
1978
1979         BoolOption* tsf;
1980
1981         tsf = new BoolOption (
1982                      "latched-record-enable",
1983                      _("Keep record-enable engaged on stop"),
1984                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_latched_record_enable),
1985                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_latched_record_enable)
1986                      );
1987         // Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _(""));
1988         add_option (_("Transport"), tsf);
1989
1990         tsf = new BoolOption (
1991                      "loop-is-mode",
1992                      _("Play loop is a transport mode"),
1993                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_loop_is_mode),
1994                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_loop_is_mode)
1995                      );
1996         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(),
1997                                             (_("<b>When enabled</b> the loop button does not start playback but forces playback to always play the loop\n\n"
1998                                                "<b>When disabled</b> the loop button starts playing the loop, but stop then cancels loop playback")));
1999         add_option (_("Transport"), tsf);
2000
2001         tsf = new BoolOption (
2002                      "stop-recording-on-xrun",
2003                      _("Stop recording when an xrun occurs"),
2004                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_recording_on_xrun),
2005                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_recording_on_xrun)
2006                      );
2007         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(),
2008                                             string_compose (_("<b>When enabled</b> %1 will stop recording if an over- or underrun is detected by the audio engine"),
2009                                                             PROGRAM_NAME));
2010         add_option (_("Transport"), tsf);
2011
2012         tsf = new BoolOption (
2013                      "create-xrun-marker",
2014                      _("Create markers where xruns occur"),
2015                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_create_xrun_marker),
2016                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_create_xrun_marker)
2017                      );
2018         // Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _(""));
2019         add_option (_("Transport"), tsf);
2020
2021         tsf = new BoolOption (
2022                      "stop-at-session-end",
2023                      _("Stop at the end of the session"),
2024                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_at_session_end),
2025                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_at_session_end)
2026                      );
2027         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(),
2028                                             string_compose (_("<b>When enabled</b> if %1 is <b>not recording</b>, it will stop the transport "
2029                                                               "when it reaches the current session end marker\n\n"
2030                                                               "<b>When disabled</b> %1 will continue to roll past the session end marker at all times"),
2031                                                             PROGRAM_NAME));
2032         add_option (_("Transport"), tsf);
2033
2034         tsf = new BoolOption (
2035                      "seamless-loop",
2036                      _("Do seamless looping (not possible when slaved to MTC, LTC etc)"),
2037                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_seamless_loop),
2038                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_seamless_loop)
2039                      );
2040         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(),
2041                                             string_compose (_("<b>When enabled</b> this will loop by reading ahead and wrapping around at the loop point, "
2042                                                               "preventing any need to do a transport locate at the end of the loop\n\n"
2043                                                               "<b>When disabled</b> looping is done by locating back to the start of the loop when %1 reaches the end "
2044                                                               "which will often cause a small click or delay"), PROGRAM_NAME));
2045         add_option (_("Transport"), tsf);
2046
2047         tsf = new BoolOption (
2048                      "disable-disarm-during-roll",
2049                      _("Disable per-track record disarm while rolling"),
2050                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_disable_disarm_during_roll),
2051                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_disable_disarm_during_roll)
2052                      );
2053         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _("<b>When enabled</b> this will prevent you from accidentally stopping specific tracks recording during a take"));
2054         add_option (_("Transport"), tsf);
2055
2056         tsf = new BoolOption (
2057                      "quieten_at_speed",
2058                      _("12dB gain reduction during fast-forward and fast-rewind"),
2059                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_quieten_at_speed),
2060                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_quieten_at_speed)
2061                      );
2062         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _("This will reduce the unpleasant increase in perceived volume "
2063                                                    "that occurs when fast-forwarding or rewinding through some kinds of audio"));
2064         add_option (_("Transport"), tsf);
2065
2066         ComboOption<float>* psc = new ComboOption<float> (
2067                      "preroll-seconds",
2068                      _("Preroll"),
2069                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_preroll_seconds),
2070                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_preroll_seconds)
2071                      );
2072         Gtkmm2ext::UI::instance()->set_tip (psc->tip_widget(),
2073                                             (_("The amount of preroll (in seconds) to apply when <b>Play with Preroll</b> is initiated.\n\n"
2074                                                "If <b>Follow Edits</b> is enabled, the preroll is applied to the playhead position when a region is selected or trimmed.")));
2075         psc->add (0.0, _("0 (no pre-roll)"));
2076         psc->add (0.1, _("0.1 second"));
2077         psc->add (0.25, _("0.25 second"));
2078         psc->add (0.5, _("0.5 second"));
2079         psc->add (1.0, _("1.0 second"));
2080         psc->add (2.0, _("2.0 seconds"));
2081         add_option (_("Transport"), psc);
2082
2083         add_option (_("Transport/Sync"), new OptionEditorHeading (S_("Synchronization and Slave Options")));
2084
2085         _sync_source = new ComboOption<SyncSource> (
2086                 "sync-source",
2087                 _("External timecode source"),
2088                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_sync_source),
2089                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_sync_source)
2090                 );
2091
2092         add_option (_("Transport/Sync"), _sync_source);
2093
2094         _sync_framerate = new BoolOption (
2095                      "timecode-sync-frame-rate",
2096                      _("Match session video frame rate to external timecode"),
2097                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_sync_frame_rate),
2098                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_sync_frame_rate)
2099                      );
2100         Gtkmm2ext::UI::instance()->set_tip
2101                 (_sync_framerate->tip_widget(),
2102                  string_compose (_("This option controls the value of the video frame rate <i>while chasing</i> an external timecode source.\n\n"
2103                                    "<b>When enabled</b> the session video frame rate will be changed to match that of the selected external timecode source.\n\n"
2104                                    "<b>When disabled</b> the session video frame rate will not be changed to match that of the selected external timecode source."
2105                                    "Instead the frame rate indication in the main clock will flash red and %1 will convert between the external "
2106                                    "timecode standard and the session standard."), PROGRAM_NAME));
2107
2108         add_option (_("Transport/Sync"), _sync_framerate);
2109
2110         _sync_genlock = new BoolOption (
2111                 "timecode-source-is-synced",
2112                 _("Sync-lock timecode to clock (disable drift compensation)"),
2113                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_is_synced),
2114                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_is_synced)
2115                 );
2116         Gtkmm2ext::UI::instance()->set_tip
2117                 (_sync_genlock->tip_widget(),
2118                  string_compose (_("<b>When enabled</b> %1 will never varispeed when slaved to external timecode. "
2119                                    "Sync Lock indicates that the selected external timecode source shares clock-sync "
2120                                    "(Black &amp; Burst, Wordclock, etc) with the audio interface. "
2121                                    "This option disables drift compensation. The transport speed is fixed at 1.0. "
2122                                    "Vari-speed LTC will be ignored and cause drift."
2123                                    "\n\n"
2124                                    "<b>When disabled</b> %1 will compensate for potential drift, regardless if the "
2125                                    "timecode sources shares clock sync."
2126                                   ), PROGRAM_NAME));
2127
2128
2129         add_option (_("Transport/Sync"), _sync_genlock);
2130
2131         _sync_source_2997 = new BoolOption (
2132                 "timecode-source-2997",
2133                 _("Lock to 29.9700 fps instead of 30000/1001"),
2134                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_2997),
2135                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_2997)
2136                 );
2137         Gtkmm2ext::UI::instance()->set_tip
2138                 (_sync_source_2997->tip_widget(),
2139                  _("<b>When enabled</b> the external timecode source is assumed to use 29.97 fps instead of 30000/1001.\n"
2140                          "SMPTE 12M-1999 specifies 29.97df as 30000/1001. The spec further mentions that "
2141                          "drop-frame timecode has an accumulated error of -86ms over a 24-hour period.\n"
2142                          "Drop-frame timecode would compensate exactly for a NTSC color frame rate of 30 * 0.9990 (ie 29.970000). "
2143                          "That is not the actual rate. However, some vendors use that rate - despite it being against the specs - "
2144                          "because the variant of using exactly 29.97 fps has zero timecode drift.\n"
2145                          ));
2146
2147         add_option (_("Transport/Sync"), _sync_source_2997);
2148
2149         add_option (_("Transport/Sync"), new OptionEditorHeading (S_("LTC Reader")));
2150
2151         _ltc_port = new ComboStringOption (
2152                 "ltc-source-port",
2153                 _("LTC incoming port"),
2154                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_source_port),
2155                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_source_port)
2156                 );
2157
2158         vector<string> physical_inputs;
2159         physical_inputs.push_back (_("None"));
2160         AudioEngine::instance()->get_physical_inputs (DataType::AUDIO, physical_inputs);
2161         _ltc_port->set_popdown_strings (physical_inputs);
2162
2163         populate_sync_options ();
2164         AudioEngine::instance()->Running.connect (engine_started_connection, MISSING_INVALIDATOR, boost::bind (&RCOptionEditor::populate_sync_options, this), gui_context());
2165
2166         add_option (_("Transport/Sync"), _ltc_port);
2167
2168         // TODO; rather disable this button than not compile it..
2169         add_option (_("Transport/Sync"), new OptionEditorHeading (S_("LTC Generator")));
2170
2171         add_option (_("Transport/Sync"),
2172                     new BoolOption (
2173                             "send-ltc",
2174                             _("Enable LTC generator"),
2175                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_ltc),
2176                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_ltc)
2177                             ));
2178
2179         _ltc_send_continuously = new BoolOption (
2180                             "ltc-send-continuously",
2181                             _("Send LTC while stopped"),
2182                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_send_continuously),
2183                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_send_continuously)
2184                             );
2185         Gtkmm2ext::UI::instance()->set_tip
2186                 (_ltc_send_continuously->tip_widget(),
2187                  string_compose (_("<b>When enabled</b> %1 will continue to send LTC information even when the transport (playhead) is not moving"), PROGRAM_NAME));
2188         add_option (_("Transport"), _ltc_send_continuously);
2189
2190         _ltc_volume_adjustment = new Gtk::Adjustment(-18, -50, 0, .5, 5);
2191         _ltc_volume_adjustment->set_value (20 * log10(_rc_config->get_ltc_output_volume()));
2192         _ltc_volume_adjustment->signal_value_changed().connect (sigc::mem_fun (*this, &RCOptionEditor::ltc_generator_volume_changed));
2193         _ltc_volume_slider = new HSliderOption("ltcvol", _("LTC generator level"), *_ltc_volume_adjustment);
2194
2195         Gtkmm2ext::UI::instance()->set_tip
2196                 (_ltc_volume_slider->tip_widget(),
2197                  _("Specify the Peak Volume of the generated LTC signal in dBFS. A good value is  0dBu ^= -18dBFS in an EBU calibrated system"));
2198
2199         add_option (_("Transport/Sync"), _ltc_volume_slider);
2200
2201         /* EDITOR */
2202
2203         add_option (_("Editor"),
2204              new BoolOption (
2205                      "rubberbanding-snaps-to-grid",
2206                      _("Make rubberband selection rectangle snap to the grid"),
2207                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_rubberbanding_snaps_to_grid),
2208                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_rubberbanding_snaps_to_grid)
2209                      ));
2210
2211         bo = new BoolOption (
2212                      "name-new-markers",
2213                      _("Name new markers"),
2214                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_name_new_markers),
2215                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_name_new_markers)
2216                 );
2217         add_option (_("Editor"), bo);
2218         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(), _("If enabled, popup a dialog when a new marker is created to allow its name to be set as it is created."
2219                                                                 "\n\nYou can always rename markers by right-clicking on them"));
2220
2221         add_option (S_("Editor"),
2222              new BoolOption (
2223                      "draggable-playhead",
2224                      _("Allow dragging of playhead"),
2225                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_draggable_playhead),
2226                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_draggable_playhead)
2227                      ));
2228
2229         add_option (_("Editor"),
2230              new BoolOption (
2231                      "show-editor-meter",
2232                      _("Display master-meter in the toolbar"),
2233                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_editor_meter),
2234                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_editor_meter)
2235                      ));
2236
2237 if (!Profile->get_mixbus()) {
2238         add_option (_("Editor"),
2239                     new BoolOption (
2240                             "show-zoom-tools",
2241                             _("Show zoom toolbar (if torn off)"),
2242                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_zoom_tools),
2243                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_zoom_tools)
2244                             ));
2245
2246         add_option (_("Editor"),
2247                     new BoolOption (
2248                             "use-mouse-position-as-zoom-focus-on-scroll",
2249                             _("Always use mouse cursor position as zoom focus when zooming using mouse scroll wheel"),
2250                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_mouse_position_as_zoom_focus_on_scroll),
2251                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_mouse_position_as_zoom_focus_on_scroll)
2252                             ));
2253 }  // !mixbus
2254
2255         add_option (_("Editor"),
2256                     new BoolOption (
2257                             "update-editor-during-summary-drag",
2258                             _("Update editor window during drags of the summary"),
2259                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_update_editor_during_summary_drag),
2260                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_update_editor_during_summary_drag)
2261                             ));
2262
2263         add_option (_("Editor"),
2264             new BoolOption (
2265                     "autoscroll-editor",
2266                     _("Auto-scroll editor window when dragging near its edges"),
2267                     sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_autoscroll_editor),
2268                     sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_autoscroll_editor)
2269                     ));
2270
2271         add_option (_("Editor"),
2272              new BoolComboOption (
2273                      "show-region-gain-envelopes",
2274                      _("Show gain envelopes in audio regions"),
2275                      _("in all modes"),
2276                      _("only in Draw and Internal Edit modes"),
2277                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_region_gain),
2278                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_region_gain)
2279                      ));
2280
2281         add_option (_("Editor"), new OptionEditorHeading (_("Editor Behavior")));
2282
2283         add_option (_("Editor"),
2284              new BoolOption (
2285                      "automation-follows-regions",
2286                      _("Move relevant automation when audio regions are moved"),
2287                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_follows_regions),
2288                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_follows_regions)
2289                      ));
2290
2291         ComboOption<FadeShape>* fadeshape = new ComboOption<FadeShape> (
2292                         "default-fade-shape",
2293                         _("Default fade shape"),
2294                         sigc::mem_fun (*_rc_config,
2295                                 &RCConfiguration::get_default_fade_shape),
2296                         sigc::mem_fun (*_rc_config,
2297                                 &RCConfiguration::set_default_fade_shape)
2298                         );
2299
2300         fadeshape->add (FadeLinear,
2301                         _("Linear (for highly correlated material)"));
2302         fadeshape->add (FadeConstantPower, _("Constant power"));
2303         fadeshape->add (FadeSymmetric, _("Symmetric"));
2304         fadeshape->add (FadeSlow, _("Slow"));
2305         fadeshape->add (FadeFast, _("Fast"));
2306
2307         add_option (_("Editor"), fadeshape);
2308
2309
2310         bco = new BoolComboOption (
2311                      "use-overlap-equivalency",
2312                      _("Regions in active edit groups are edited together"),
2313                      _("whenever they overlap in time"),
2314                      _("only if they have identical length, position and origin"),
2315                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_use_overlap_equivalency),
2316                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_use_overlap_equivalency)
2317                      );
2318
2319         add_option (_("Editor"), bco);
2320
2321         ComboOption<LayerModel>* lm = new ComboOption<LayerModel> (
2322                 "layer-model",
2323                 _("Layering model"),
2324                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_layer_model),
2325                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_layer_model)
2326                 );
2327
2328         lm->add (LaterHigher, _("later is higher"));
2329         lm->add (Manual, _("manual layering"));
2330         add_option (_("Editor"), lm);
2331
2332         ComboOption<RegionSelectionAfterSplit> *rsas = new ComboOption<RegionSelectionAfterSplit> (
2333                     "region-selection-after-split",
2334                     _("After splitting selected regions, select"),
2335                     sigc::mem_fun (*_rc_config, &RCConfiguration::get_region_selection_after_split),
2336                     sigc::mem_fun (*_rc_config, &RCConfiguration::set_region_selection_after_split));
2337
2338         // TODO: decide which of these modes are really useful
2339         rsas->add(None, _("no regions"));
2340         // rsas->add(NewlyCreatedLeft, _("newly-created regions before the split"));
2341         // rsas->add(NewlyCreatedRight, _("newly-created regions after the split"));
2342         rsas->add(NewlyCreatedBoth, _("newly-created regions"));
2343         // rsas->add(Existing, _("unmodified regions in the existing selection"));
2344         // rsas->add(ExistingNewlyCreatedLeft, _("existing selection and newly-created regions before the split"));
2345         // rsas->add(ExistingNewlyCreatedRight, _("existing selection and newly-created regions after the split"));
2346         rsas->add(ExistingNewlyCreatedBoth, _("existing selection and newly-created regions"));
2347
2348         add_option (_("Editor"), rsas);
2349
2350         add_option (_("Editor/Waveforms"), new OptionEditorHeading (_("Waveforms")));
2351
2352 if (!Profile->get_mixbus()) {
2353         add_option (_("Editor/Waveforms"),
2354              new BoolOption (
2355                      "show-waveforms",
2356                      _("Show waveforms in regions"),
2357                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveforms),
2358                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveforms)
2359                      ));
2360 }  // !mixbus
2361
2362         add_option (_("Editor/Waveforms"),
2363              new BoolOption (
2364                      "show-waveforms-while-recording",
2365                      _("Show waveforms for audio while it is being recorded"),
2366                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveforms_while_recording),
2367                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveforms_while_recording)
2368                      ));
2369
2370         ComboOption<WaveformScale>* wfs = new ComboOption<WaveformScale> (
2371                 "waveform-scale",
2372                 _("Waveform scale"),
2373                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_scale),
2374                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_scale)
2375                 );
2376
2377         wfs->add (Linear, _("linear"));
2378         wfs->add (Logarithmic, _("logarithmic"));
2379
2380         add_option (_("Editor/Waveforms"), wfs);
2381
2382         ComboOption<WaveformShape>* wfsh = new ComboOption<WaveformShape> (
2383                 "waveform-shape",
2384                 _("Waveform shape"),
2385                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_shape),
2386                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_shape)
2387                 );
2388
2389         wfsh->add (Traditional, _("traditional"));
2390         wfsh->add (Rectified, _("rectified"));
2391
2392         add_option (_("Editor/Waveforms"), wfsh);
2393
2394         add_option (_("Editor/Waveforms"), new ClipLevelOptions ());
2395
2396
2397         /* AUDIO */
2398
2399         add_option (_("Audio"), new OptionEditorHeading (_("Buffering")));
2400
2401         add_option (_("Audio"), new BufferingOptions (_rc_config));
2402
2403         add_option (_("Audio"), new OptionEditorHeading (_("Monitoring")));
2404
2405         ComboOption<MonitorModel>* mm = new ComboOption<MonitorModel> (
2406                 "monitoring-model",
2407                 _("Record monitoring handled by"),
2408                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_monitoring_model),
2409                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_monitoring_model)
2410                 );
2411
2412         if (AudioEngine::instance()->port_engine().can_monitor_input()) {
2413                 mm->add (HardwareMonitoring, _("via Audio Driver"));
2414         }
2415
2416         string prog (PROGRAM_NAME);
2417         boost::algorithm::to_lower (prog);
2418         mm->add (SoftwareMonitoring, string_compose (_("%1"), prog));
2419         mm->add (ExternalMonitoring, _("audio hardware"));
2420
2421         add_option (_("Audio"), mm);
2422
2423         add_option (_("Audio"),
2424              new BoolOption (
2425                      "tape-machine-mode",
2426                      _("Tape machine mode"),
2427                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_tape_machine_mode),
2428                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_tape_machine_mode)
2429                      ));
2430
2431         add_option (_("Audio"), new OptionEditorHeading (_("Connection of tracks and busses")));
2432 if (!Profile->get_mixbus()) {
2433
2434         add_option (_("Audio"),
2435                     new BoolOption (
2436                             "auto-connect-standard-busses",
2437                             _("Auto-connect master/monitor busses"),
2438                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_connect_standard_busses),
2439                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_connect_standard_busses)
2440                             ));
2441
2442         ComboOption<AutoConnectOption>* iac = new ComboOption<AutoConnectOption> (
2443                 "input-auto-connect",
2444                 _("Connect track inputs"),
2445                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_input_auto_connect),
2446                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_input_auto_connect)
2447                 );
2448
2449         iac->add (AutoConnectPhysical, _("automatically to physical inputs"));
2450         iac->add (ManualConnect, _("manually"));
2451
2452         add_option (_("Audio"), iac);
2453
2454         ComboOption<AutoConnectOption>* oac = new ComboOption<AutoConnectOption> (
2455                 "output-auto-connect",
2456                 _("Connect track and bus outputs"),
2457                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_output_auto_connect),
2458                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_output_auto_connect)
2459                 );
2460
2461         oac->add (AutoConnectPhysical, _("automatically to physical outputs"));
2462         oac->add (AutoConnectMaster, _("automatically to master bus"));
2463         oac->add (ManualConnect, _("manually"));
2464
2465         add_option (_("Audio"), oac);
2466
2467         bo = new BoolOption (
2468                         "strict-io",
2469                         _("Use 'Strict-I/O' for new tracks or Busses"),
2470                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_strict_io),
2471                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_strict_io)
2472                         );
2473
2474         add_option (_("Audio"), bo);
2475         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2476                         _("With strict-i/o enabled, Effect Processors will not modify the number of channels on a track. The number of output channels will always match the number of input channels."));
2477
2478 }  // !mixbus
2479
2480         add_option (_("Audio"), new OptionEditorHeading (_("Denormals")));
2481
2482         add_option (_("Audio"),
2483              new BoolOption (
2484                      "denormal-protection",
2485                      _("Use DC bias to protect against denormals"),
2486                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_protection),
2487                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_protection)
2488                      ));
2489
2490         ComboOption<DenormalModel>* dm = new ComboOption<DenormalModel> (
2491                 "denormal-model",
2492                 _("Processor handling"),
2493                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_model),
2494                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_model)
2495                 );
2496
2497         int dmsize = 1;
2498         dm->add (DenormalNone, _("no processor handling"));
2499
2500         FPU* fpu = FPU::instance();
2501
2502         if (fpu->has_flush_to_zero()) {
2503                 ++dmsize;
2504                 dm->add (DenormalFTZ, _("use FlushToZero"));
2505         } else if (_rc_config->get_denormal_model() == DenormalFTZ) {
2506                 _rc_config->set_denormal_model(DenormalNone);
2507         }
2508
2509         if (fpu->has_denormals_are_zero()) {
2510                 ++dmsize;
2511                 dm->add (DenormalDAZ, _("use DenormalsAreZero"));
2512         } else if (_rc_config->get_denormal_model() == DenormalDAZ) {
2513                 _rc_config->set_denormal_model(DenormalNone);
2514         }
2515
2516         if (fpu->has_flush_to_zero() && fpu->has_denormals_are_zero()) {
2517                 ++dmsize;
2518                 dm->add (DenormalFTZDAZ, _("use FlushToZero and DenormalsAreZero"));
2519         } else if (_rc_config->get_denormal_model() == DenormalFTZDAZ) {
2520                 _rc_config->set_denormal_model(DenormalNone);
2521         }
2522
2523         if (dmsize == 1) {
2524                 dm->set_sensitive(false);
2525         }
2526
2527         add_option (_("Audio"), dm);
2528
2529         add_option (_("Audio"), new OptionEditorHeading (_("Regions")));
2530
2531         add_option (_("Audio"),
2532              new BoolOption (
2533                      "auto-analyse-audio",
2534                      _("Enable automatic analysis of audio"),
2535                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_analyse_audio),
2536                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_analyse_audio)
2537                      ));
2538
2539         add_option (_("Audio"),
2540              new BoolOption (
2541                      "replicate-missing-region-channels",
2542                      _("Replicate missing region channels"),
2543                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_replicate_missing_region_channels),
2544                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_replicate_missing_region_channels)
2545                      ));
2546
2547         /* SOLO AND MUTE */
2548
2549         add_option (_("Solo & mute"), new OptionEditorHeading (_("Solo")));
2550
2551         _solo_control_is_listen_control = new BoolOption (
2552                 "solo-control-is-listen-control",
2553                 _("Solo controls are Listen controls"),
2554                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_control_is_listen_control),
2555                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_control_is_listen_control)
2556                 );
2557
2558         add_option (_("Solo & mute"), _solo_control_is_listen_control);
2559
2560         add_option (_("Solo & mute"),
2561              new BoolOption (
2562                      "exclusive-solo",
2563                      _("Exclusive solo"),
2564                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_exclusive_solo),
2565                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_exclusive_solo)
2566                      ));
2567
2568         add_option (_("Solo & mute"),
2569              new BoolOption (
2570                      "show-solo-mutes",
2571                      _("Show solo muting"),
2572                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_show_solo_mutes),
2573                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_solo_mutes)
2574                      ));
2575
2576         add_option (_("Solo & mute"),
2577              new BoolOption (
2578                      "solo-mute-override",
2579                      _("Soloing overrides muting"),
2580                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_override),
2581                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_override)
2582                      ));
2583
2584         add_option (_("Solo & mute"),
2585              new FaderOption (
2586                      "solo-mute-gain",
2587                      _("Solo-in-place mute cut (dB)"),
2588                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_gain),
2589                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_gain)
2590                      ));
2591
2592         _listen_position = new ComboOption<ListenPosition> (
2593                 "listen-position",
2594                 _("Listen Position"),
2595                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_listen_position),
2596                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_listen_position)
2597                 );
2598
2599         _listen_position->add (AfterFaderListen, _("after-fader (AFL)"));
2600         _listen_position->add (PreFaderListen, _("pre-fader (PFL)"));
2601
2602         add_option (_("Solo & mute"), _listen_position);
2603
2604         ComboOption<PFLPosition>* pp = new ComboOption<PFLPosition> (
2605                 "pfl-position",
2606                 _("PFL signals come from"),
2607                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_pfl_position),
2608                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_pfl_position)
2609                 );
2610
2611         pp->add (PFLFromBeforeProcessors, _("before pre-fader processors"));
2612         pp->add (PFLFromAfterProcessors, _("pre-fader but after pre-fader processors"));
2613
2614         add_option (_("Solo & mute"), pp);
2615
2616         ComboOption<AFLPosition>* pa = new ComboOption<AFLPosition> (
2617                 "afl-position",
2618                 _("AFL signals come from"),
2619                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_afl_position),
2620                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_afl_position)
2621                 );
2622
2623         pa->add (AFLFromBeforeProcessors, _("immediately post-fader"));
2624         pa->add (AFLFromAfterProcessors, _("after post-fader processors (before pan)"));
2625
2626         add_option (_("Solo & mute"), pa);
2627
2628         add_option (_("Solo & mute"), new OptionEditorHeading (_("Default track / bus muting options")));
2629
2630         add_option (_("Solo & mute"),
2631              new BoolOption (
2632                      "mute-affects-pre-fader",
2633                      _("Mute affects pre-fader sends"),
2634                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_pre_fader),
2635                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_pre_fader)
2636                      ));
2637
2638         add_option (_("Solo & mute"),
2639              new BoolOption (
2640                      "mute-affects-post-fader",
2641                      _("Mute affects post-fader sends"),
2642                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_post_fader),
2643                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_post_fader)
2644                      ));
2645
2646         add_option (_("Solo & mute"),
2647              new BoolOption (
2648                      "mute-affects-control-outs",
2649                      _("Mute affects control outputs"),
2650                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_control_outs),
2651                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_control_outs)
2652                      ));
2653
2654         add_option (_("Solo & mute"),
2655              new BoolOption (
2656                      "mute-affects-main-outs",
2657                      _("Mute affects main outputs"),
2658                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_main_outs),
2659                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_main_outs)
2660                      ));
2661
2662
2663 if (!ARDOUR::Profile->get_mixbus()) {
2664         add_option (_("Solo & mute"), new OptionEditorHeading (_("Send Routing")));
2665         add_option (_("Solo & mute"),
2666              new BoolOption (
2667                      "link-send-and-route-panner",
2668                      _("Link panners of Aux and External Sends with main panner by default"),
2669                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_link_send_and_route_panner),
2670                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_link_send_and_route_panner)
2671                      ));
2672 }
2673
2674         add_option (_("MIDI"), new OptionEditorHeading (_("MIDI Preferences")));
2675
2676         add_option (_("MIDI"),
2677                     new SpinOption<float> (
2678                             "midi-readahead",
2679                             _("MIDI read-ahead time (seconds)"),
2680                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_readahead),
2681                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_readahead),
2682                             0.1, 10, 0.1, 1,
2683                             "", 1.0, 1
2684                             ));
2685
2686         add_option (_("MIDI"),
2687              new SpinOption<int32_t> (
2688                      "initial-program-change",
2689                      _("Initial program change"),
2690                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_initial_program_change),
2691                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_initial_program_change),
2692                      -1, 65536, 1, 10
2693                      ));
2694
2695         add_option (_("MIDI"),
2696                     new BoolOption (
2697                             "display-first-midi-bank-as-zero",
2698                             _("Display first MIDI bank/program as 0"),
2699                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_first_midi_bank_is_zero),
2700                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_first_midi_bank_is_zero)
2701                             ));
2702
2703         add_option (_("MIDI"),
2704              new BoolOption (
2705                      "never-display-periodic-midi",
2706                      _("Never display periodic MIDI messages (MTC, MIDI Clock)"),
2707                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_never_display_periodic_midi),
2708                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_never_display_periodic_midi)
2709                      ));
2710
2711         add_option (_("MIDI"),
2712              new BoolOption (
2713                      "sound-midi-notes",
2714                      _("Sound MIDI notes as they are selected in the editor"),
2715                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_sound_midi_notes),
2716                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_sound_midi_notes)
2717                      ));
2718
2719         add_option (_("MIDI"),
2720                     new BoolOption (
2721                             "midi-feedback",
2722                             _("Send MIDI control feedback"),
2723                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_feedback),
2724                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_feedback)
2725                             ));
2726
2727         add_option (_("MIDI/Sync"), new OptionEditorHeading (_("MIDI Clock")));
2728
2729         add_option (_("MIDI/Sync"),
2730                     new BoolOption (
2731                             "send-midi-clock",
2732                             _("Send MIDI Clock"),
2733                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_midi_clock),
2734                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_midi_clock)
2735                             ));
2736
2737         add_option (_("MIDI/Sync"), new OptionEditorHeading (_("MIDI Time Code (MTC)")));
2738
2739         add_option (_("MIDI/Sync"),
2740                     new BoolOption (
2741                             "send-mtc",
2742                             _("Send MIDI Time Code"),
2743                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mtc),
2744                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mtc)
2745                             ));
2746
2747         add_option (_("MIDI/Sync"),
2748                     new SpinOption<int> (
2749                             "mtc-qf-speed-tolerance",
2750                             _("Percentage either side of normal transport speed to transmit MTC"),
2751                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mtc_qf_speed_tolerance),
2752                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mtc_qf_speed_tolerance),
2753                             0, 20, 1, 5
2754                             ));
2755
2756         add_option (_("MIDI/Sync"), new OptionEditorHeading (_("Midi Machine Control (MMC)")));
2757
2758         add_option (_("MIDI/Sync"),
2759                     new BoolOption (
2760                             "mmc-control",
2761                             _("Obey MIDI Machine Control commands"),
2762                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_control),
2763                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_control)
2764                             ));
2765
2766         add_option (_("MIDI/Sync"),
2767                     new BoolOption (
2768                             "send-mmc",
2769                             _("Send MIDI Machine Control commands"),
2770                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mmc),
2771                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mmc)
2772                             ));
2773
2774         add_option (_("MIDI/Sync"),
2775              new SpinOption<uint8_t> (
2776                      "mmc-receive-device-id",
2777                      _("Inbound MMC device ID"),
2778                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_receive_device_id),
2779                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_receive_device_id),
2780                      0, 128, 1, 10
2781                      ));
2782
2783         add_option (_("MIDI/Sync"),
2784              new SpinOption<uint8_t> (
2785                      "mmc-send-device-id",
2786                      _("Outbound MMC device ID"),
2787                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_send_device_id),
2788                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_send_device_id),
2789                      0, 128, 1, 10
2790                      ));
2791
2792         add_option (_("MIDI"), new OptionEditorHeading (_("Midi Audition")));
2793
2794         ComboOption<std::string>* audition_synth = new ComboOption<std::string> (
2795                 "midi-audition-synth-uri",
2796                 _("Midi Audition Synth (LV2)"),
2797                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_audition_synth_uri),
2798                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_audition_synth_uri)
2799                 );
2800
2801         audition_synth->add(X_(""), _("None"));
2802         PluginInfoList all_plugs;
2803         PluginManager& manager (PluginManager::instance());
2804 #ifdef LV2_SUPPORT
2805         all_plugs.insert (all_plugs.end(), manager.lv2_plugin_info().begin(), manager.lv2_plugin_info().end());
2806
2807         for (PluginInfoList::const_iterator i = all_plugs.begin(); i != all_plugs.end(); ++i) {
2808                 if (manager.get_status (*i) == PluginManager::Hidden) continue;
2809                 if (!(*i)->is_instrument()) continue;
2810                 if ((*i)->type != ARDOUR::LV2) continue;
2811                 audition_synth->add((*i)->unique_id, (*i)->name);
2812         }
2813 #endif
2814
2815         add_option (_("MIDI"), audition_synth);
2816
2817         /* USER INTERACTION */
2818
2819         if (
2820 #ifdef PLATFORM_WINDOWS
2821                         true
2822 #else
2823                         getenv ("ARDOUR_BUNDLED")
2824 #endif
2825            )
2826         {
2827                 add_option (_("User interaction"),
2828                             new BoolOption (
2829                                     "enable-translation",
2830                                     string_compose (_("Use translations of %1 messages\n"
2831                                                       "   <i>(requires a restart of %1 to take effect)</i>\n"
2832                                                       "   <i>(if available for your language preferences)</i>"), PROGRAM_NAME),
2833                                     sigc::ptr_fun (ARDOUR::translations_are_enabled),
2834                                     sigc::ptr_fun (ARDOUR::set_translations_enabled)));
2835         }
2836
2837         add_option (_("User interaction"), new OptionEditorHeading (_("Keyboard")));
2838
2839         add_option (_("User interaction"), new KeyboardOptions);
2840
2841         /* Control Surfaces */
2842
2843         add_option (_("Control Surfaces"), new ControlSurfacesOptions);
2844
2845         /* VIDEO Timeline */
2846         add_option (_("Video"), new VideoTimelineOptions (_rc_config));
2847
2848 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined AUDIOUNIT_SUPPORT)
2849         add_option (_("Plugins"),
2850                         new RcActionButton (_("Scan for Plugins"),
2851                                 sigc::mem_fun (*this, &RCOptionEditor::plugin_scan_refresh)));
2852
2853 #endif
2854
2855         add_option (_("Plugins"), new OptionEditorHeading (_("General")));
2856
2857 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined AUDIOUNIT_SUPPORT)
2858         bo = new BoolOption (
2859                         "show-plugin-scan-window",
2860                         _("Always Display Plugin Scan Progress"),
2861                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_plugin_scan_window),
2862                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_plugin_scan_window)
2863                         );
2864         add_option (_("Plugins"), bo);
2865         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2866                         _("<b>When enabled</b> a popup window showing plugin scan progress is displayed for indexing (cache load) and discovery (detect new plugins)"));
2867 #endif
2868
2869         bo = new BoolOption (
2870                 "plugins-stop-with-transport",
2871                 _("Silence plugins when the transport is stopped"),
2872                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugins_stop_with_transport),
2873                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_plugins_stop_with_transport)
2874                 );
2875         add_option (_("Plugins"), bo);
2876         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2877                                             _("<b>When enabled</b> plugins will be reset at transport stop. When disabled plugins will be left unchanged at transport stop.\n\nThis mostly affects plugins with a \"tail\" like Reverbs."));
2878
2879         bo = new BoolOption (
2880                 "new-plugins-active",
2881                         _("Make new plugins active"),
2882                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_new_plugins_active),
2883                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_new_plugins_active)
2884                         );
2885         add_option (_("Plugins"), bo);
2886         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2887                                             _("<b>When enabled</b> plugins will be activated when they are added to tracks/busses. When disabled plugins will be left inactive when they are added to tracks/busses"));
2888
2889 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
2890         add_option (_("Plugins/VST"), new OptionEditorHeading (_("VST")));
2891         add_option (_("Plugins/VST"),
2892                         new RcActionButton (_("Scan for Plugins"),
2893                                 sigc::mem_fun (*this, &RCOptionEditor::plugin_scan_refresh)));
2894
2895         bo = new BoolOption (
2896                         "discover-vst-on-start",
2897                         _("Scan for [new] VST Plugins on Application Start"),
2898                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_discover_vst_on_start),
2899                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_discover_vst_on_start)
2900                         );
2901         add_option (_("Plugins/VST"), bo);
2902         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2903                                             _("<b>When enabled</b> new VST plugins are searched, tested and added to the cache index on application start. When disabled new plugins will only be available after triggering a 'Scan' manually"));
2904
2905 #ifdef WINDOWS_VST_SUPPORT
2906         // currently verbose logging is only implemented for Windows VST.
2907         bo = new BoolOption (
2908                         "verbose-plugin-scan",
2909                         _("Verbose Plugin Scan"),
2910                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_verbose_plugin_scan),
2911                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_verbose_plugin_scan)
2912                         );
2913         add_option (_("Plugins/VST"), bo);
2914         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2915                                             _("<b>When enabled</b> additional information for every plugin is added to the Log Window."));
2916 #endif
2917
2918         add_option (_("Plugins/VST"), new VstTimeOutSliderOption (_rc_config));
2919
2920         add_option (_("Plugins/VST"),
2921                         new RcActionButton (_("Clear"),
2922                                 sigc::mem_fun (*this, &RCOptionEditor::clear_vst_cache),
2923                                 _("VST Cache:")));
2924
2925         add_option (_("Plugins/VST"),
2926                         new RcActionButton (_("Clear"),
2927                                 sigc::mem_fun (*this, &RCOptionEditor::clear_vst_blacklist),
2928                                 _("VST Blacklist:")));
2929 #endif
2930
2931 #ifdef LXVST_SUPPORT
2932         add_option (_("Plugins/VST"),
2933                         new RcActionButton (_("Edit"),
2934                                 sigc::mem_fun (*this, &RCOptionEditor::edit_lxvst_path),
2935                         _("Linux VST Path:")));
2936
2937         add_option (_("Plugins/VST"),
2938                         new RcConfigDisplay (
2939                                 "plugin-path-lxvst",
2940                                 _("Path:"),
2941                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugin_path_lxvst),
2942                                 0));
2943 #endif
2944
2945 #ifdef WINDOWS_VST_SUPPORT
2946         add_option (_("Plugins/VST"),
2947                         new RcActionButton (_("Edit"),
2948                                 sigc::mem_fun (*this, &RCOptionEditor::edit_vst_path),
2949                         _("Windows VST Path:")));
2950         add_option (_("Plugins"),
2951                         new RcConfigDisplay (
2952                                 "plugin-path-vst",
2953                                 _("Path:"),
2954                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugin_path_vst),
2955                                 ';'));
2956 #endif
2957
2958 #ifdef AUDIOUNIT_SUPPORT
2959
2960         add_option (_("Plugins/Audio Unit"), new OptionEditorHeading (_("Audio Unit")));
2961         add_option (_("Plugins/Audio Unit"),
2962                         new RcActionButton (_("Scan for Plugins"),
2963                                 sigc::mem_fun (*this, &RCOptionEditor::plugin_scan_refresh)));
2964
2965         bo = new BoolOption (
2966                         "discover-audio-units",
2967                         _("Scan for AudioUnit Plugins on Application Start"),
2968                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_discover_audio_units),
2969                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_discover_audio_units)
2970                         );
2971         add_option (_("Plugins"), bo);
2972         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2973                                             _("<b>When enabled</b> Audio Unit Plugins are discovered on application start. When disabled AU plugins will only be available after triggering a 'Scan' manually. The first successful scan will enable AU auto-scan, Any crash during plugin discovery will disable it."));
2974
2975         add_option (_("Plugins/Audio Unit"),
2976                         new RcActionButton (_("Clear"),
2977                                 sigc::mem_fun (*this, &RCOptionEditor::clear_au_cache),
2978                                 _("AU Cache:")));
2979
2980         add_option (_("Plugins/Audio Unit"),
2981                         new RcActionButton (_("Clear"),
2982                                 sigc::mem_fun (*this, &RCOptionEditor::clear_au_blacklist),
2983                                 _("AU Blacklist:")));
2984 #endif
2985
2986 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined AUDIOUNIT_SUPPORT || defined HAVE_LV2)
2987         add_option (_("Plugins"), new OptionEditorHeading (_("Plugin GUI")));
2988         add_option (_("Plugins"),
2989              new BoolOption (
2990                      "open-gui-after-adding-plugin",
2991                      _("Automatically open the plugin GUI when adding a new plugin"),
2992                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_open_gui_after_adding_plugin),
2993                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_open_gui_after_adding_plugin)
2994                      ));
2995
2996 #if (defined LV2_SUPPORT && defined LV2_EXTENDED)
2997         add_option (_("Plugins"),
2998              new BoolOption (
2999                      "show-inline-display-by-default",
3000                      _("Show Plugin Inline Display on Mixerstrip by default"),
3001                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_inline_display_by_default),
3002                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_inline_display_by_default)
3003                      ));
3004
3005         _plugin_prefer_inline = new BoolOption (
3006                         "prefer-inline-over-gui",
3007                         _("Don't automatically open the plugin GUI when the plugin has an inline display mode"),
3008                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_prefer_inline_over_gui),
3009                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_prefer_inline_over_gui)
3010                         );
3011         add_option (_("Plugins"), _plugin_prefer_inline);
3012 #endif
3013
3014         add_option (_("Plugins"), new OptionEditorHeading (_("Instrument")));
3015
3016         bo = new BoolOption (
3017                         "ask-replace-instrument",
3018                         _("Ask to replace existing instrument plugin"),
3019                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_ask_replace_instrument),
3020                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_ask_replace_instrument)
3021                         );
3022         add_option (_("Plugins"), bo);
3023
3024         bo = new BoolOption (
3025                         "ask-setup_instrument",
3026                         _("Interactively configure instrument plugins on insert"),
3027                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_ask_setup_instrument),
3028                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_ask_setup_instrument)
3029                         );
3030         add_option (_("Plugins"), bo);
3031         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3032                         _("<b>When enabled</b> show a dialog to select instrument channel configuration before adding a multichannel plugin."));
3033
3034 #endif
3035
3036         /* INTERFACE */
3037
3038 #ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
3039         BoolOption* bgc = new BoolOption (
3040                 "cairo-image-surface",
3041                 _("Disable Graphics Hardware Acceleration (requires restart)"),
3042                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_cairo_image_surface),
3043                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_cairo_image_surface)
3044                 );
3045
3046         Gtkmm2ext::UI::instance()->set_tip (bgc->tip_widget(), string_compose (
3047                                 _("Render large parts of the application user-interface in software, instead of using 2D-graphics acceleration.\nThis requires restarting %1 before having an effect"), PROGRAM_NAME));
3048         add_option (S_("Preferences|GUI"), bgc);
3049 #endif
3050
3051 #ifdef CAIRO_SUPPORTS_FORCE_BUGGY_GRADIENTS_ENVIRONMENT_VARIABLE
3052         BoolOption* bgo = new BoolOption (
3053                 "buggy-gradients",
3054                 _("Possibly improve slow graphical performance (requires restart)"),
3055                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_buggy_gradients),
3056                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_buggy_gradients)
3057                 );
3058
3059         Gtkmm2ext::UI::instance()->set_tip (bgo->tip_widget(), string_compose (_("Disables hardware gradient rendering on buggy video drivers (\"buggy gradients patch\").\nThis requires restarting %1 before having an effect"), PROGRAM_NAME));
3060         add_option (S_("Preferences|GUI"), bgo);
3061 #endif
3062
3063         add_option (S_("Preferences|GUI"),
3064              new BoolOption (
3065                      "use-wm-visibility",
3066                      _("Use Window Manager/Desktop visibility information"),
3067                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_wm_visibility),
3068                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_wm_visibility)
3069                      ));
3070
3071         add_option (S_("Preferences|GUI"),
3072              new BoolOption (
3073                      "widget-prelight",
3074                      _("Graphically indicate mouse pointer hovering over various widgets"),
3075                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_widget_prelight),
3076                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_widget_prelight)
3077                      ));
3078
3079         add_option (S_("Preferences|GUI"),
3080              new BoolOption (
3081                      "use-tooltips",
3082                      _("Show tooltips if mouse hovers over a control"),
3083                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_tooltips),
3084                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_tooltips)
3085                      ));
3086
3087         add_option (S_("Preferences|GUI"),
3088              new BoolOption (
3089                      "show-name-highlight",
3090                      _("Use name highlight bars in region displays (requires a restart)"),
3091                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_name_highlight),
3092                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_name_highlight)
3093                      ));
3094
3095         add_option (S_("Preferences|GUI"),
3096                     new BoolOption (
3097                             "super-rapid-clock-update",
3098                             _("Update transport clock display at FPS instead of every 100ms"),
3099                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_super_rapid_clock_update),
3100                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_super_rapid_clock_update)
3101                             ));
3102
3103
3104 #ifndef __APPLE__
3105         /* font scaling does nothing with GDK/Quartz */
3106         add_option (S_("Preferences|GUI"), new FontScalingOptions ());
3107 #endif
3108
3109         /* Image cache size */
3110
3111         Gtk::Adjustment *ics = manage (new Gtk::Adjustment(0, 1, 1024, 10)); /* 1 MB to 1GB in steps of 10MB */
3112         HSliderOption *sics = new HSliderOption("waveform-cache-size",
3113                                                 _("Waveform image cache size (megabytes)"),
3114                                                 ics,
3115                                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_cache_size),
3116                                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_cache_size)
3117                         );
3118         sics->scale().set_digits (0);
3119         Gtkmm2ext::UI::instance()->set_tip
3120                 (sics->tip_widget(),
3121                  _("Increasing the cache size uses more memory to store waveform images, which can improve graphical performance."));
3122         add_option (S_("Preferences|GUI"), sics);
3123
3124 if (!ARDOUR::Profile->get_mixbus()) {
3125         /* Lock GUI timeout */
3126
3127         Gtk::Adjustment *lts = manage (new Gtk::Adjustment(0, 0, 1000, 1, 10));
3128         HSliderOption *slts = new HSliderOption("lock-gui-after-seconds",
3129                                                 _("Lock timeout (seconds)"),
3130                                                 lts,
3131                                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_lock_gui_after_seconds),
3132                                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_lock_gui_after_seconds)
3133                         );
3134         slts->scale().set_digits (0);
3135         Gtkmm2ext::UI::instance()->set_tip
3136                 (slts->tip_widget(),
3137                  _("Lock GUI after this many idle seconds (zero to never lock)"));
3138         add_option (S_("Preferences|GUI"), slts);
3139 } // !mixbus
3140
3141         /* The names of these controls must be the same as those given in MixerStrip
3142            for the actual widgets being controlled.
3143         */
3144         _mixer_strip_visibility.add (0, X_("Input"), _("Input"));
3145         _mixer_strip_visibility.add (0, X_("PhaseInvert"), _("Phase Invert"));
3146         _mixer_strip_visibility.add (0, X_("RecMon"), _("Record & Monitor"));
3147         _mixer_strip_visibility.add (0, X_("SoloIsoLock"), _("Solo Iso / Lock"));
3148         _mixer_strip_visibility.add (0, X_("Output"), _("Output"));
3149         _mixer_strip_visibility.add (0, X_("Comments"), _("Comments"));
3150         _mixer_strip_visibility.add (0, X_("VCA"), _("VCA Assigns"));
3151
3152         add_option (
3153                 S_("Preferences|GUI"),
3154                 new VisibilityOption (
3155                         _("Mixer Strip"),
3156                         &_mixer_strip_visibility,
3157                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_mixer_strip_visibility),
3158                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_mixer_strip_visibility)
3159                         )
3160                 );
3161
3162         add_option (S_("Preferences|GUI"),
3163              new BoolOption (
3164                      "default-narrow_ms",
3165                      _("Use narrow strips in the mixer by default"),
3166                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_default_narrow_ms),
3167                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_default_narrow_ms)
3168                      ));
3169
3170         add_option (S_("Preferences|GUI"),
3171                         new ColumVisibilityOption (
3172                                 "action-table-columns", _("Action Script Button Visibility"), 3,
3173                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_action_table_columns),
3174                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_action_table_columns)
3175                                 )
3176                         );
3177
3178         add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Metering")));
3179
3180         ComboOption<float>* mht = new ComboOption<float> (
3181                 "meter-hold",
3182                 _("Peak hold time"),
3183                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_hold),
3184                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_hold)
3185                 );
3186
3187         mht->add (MeterHoldOff, _("off"));
3188         mht->add (MeterHoldShort, _("short"));
3189         mht->add (MeterHoldMedium, _("medium"));
3190         mht->add (MeterHoldLong, _("long"));
3191
3192         add_option (S_("Preferences|Metering"), mht);
3193
3194         ComboOption<float>* mfo = new ComboOption<float> (
3195                 "meter-falloff",
3196                 _("DPM fall-off"),
3197                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_falloff),
3198                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_falloff)
3199                 );
3200
3201         mfo->add (METER_FALLOFF_OFF,      _("off"));
3202         mfo->add (METER_FALLOFF_SLOWEST,  _("slowest [6.6dB/sec]"));
3203         mfo->add (METER_FALLOFF_SLOW,     _("slow [8.6dB/sec] (BBC PPM, EBU PPM)"));
3204         mfo->add (METER_FALLOFF_SLOWISH,  _("moderate [12.0dB/sec] (DIN)"));
3205         mfo->add (METER_FALLOFF_MODERATE, _("medium [13.3dB/sec] (EBU Digi PPM, IRT Digi PPM)"));
3206         mfo->add (METER_FALLOFF_MEDIUM,   _("fast [20dB/sec]"));
3207         mfo->add (METER_FALLOFF_FAST,     _("very fast [32dB/sec]"));
3208
3209         add_option (S_("Preferences|Metering"), mfo);
3210
3211         ComboOption<MeterLineUp>* mlu = new ComboOption<MeterLineUp> (
3212                 "meter-line-up-level",
3213                 _("Meter line-up level; 0dBu"),
3214                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_line_up_level),
3215                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_line_up_level)
3216                 );
3217
3218         mlu->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
3219         mlu->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
3220         mlu->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
3221         mlu->add (MeteringLineUp15, _("-15dBFS (DIN)"));
3222
3223         Gtkmm2ext::UI::instance()->set_tip (mlu->tip_widget(), _("Configure meter-marks and color-knee point for dBFS scale DPM, set reference level for IEC1/Nordic, IEC2 PPM and VU meter."));
3224
3225         add_option (S_("Preferences|Metering"), mlu);
3226
3227         ComboOption<MeterLineUp>* mld = new ComboOption<MeterLineUp> (
3228                 "meter-line-up-din",
3229                 _("IEC1/DIN Meter line-up level; 0dBu"),
3230                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_line_up_din),
3231                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_line_up_din)
3232                 );
3233
3234         mld->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
3235         mld->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
3236         mld->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
3237         mld->add (MeteringLineUp15, _("-15dBFS (DIN)"));
3238
3239         Gtkmm2ext::UI::instance()->set_tip (mld->tip_widget(), _("Reference level for IEC1/DIN meter."));
3240
3241         add_option (S_("Preferences|Metering"), mld);
3242
3243         ComboOption<VUMeterStandard>* mvu = new ComboOption<VUMeterStandard> (
3244                 "meter-vu-standard",
3245                 _("VU Meter standard"),
3246                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_vu_standard),
3247                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_vu_standard)
3248                 );
3249
3250         mvu->add (MeteringVUfrench,   _("0VU = -2dBu (France)"));
3251         mvu->add (MeteringVUamerican, _("0VU = 0dBu (North America, Australia)"));
3252         mvu->add (MeteringVUstandard, _("0VU = +4dBu (standard)"));
3253         mvu->add (MeteringVUeight,    _("0VU = +8dBu"));
3254
3255         add_option (S_("Preferences|Metering"), mvu);
3256
3257         Gtk::Adjustment *mpk = manage (new Gtk::Adjustment(0, -10, 0, .1, .1));
3258         HSliderOption *mpks = new HSliderOption("meter-peak",
3259                         _("Peak threshold [dBFS]"),
3260                         mpk,
3261                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_peak),
3262                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_peak)
3263                         );
3264
3265
3266         ComboOption<MeterType>* mtm = new ComboOption<MeterType> (
3267                 "meter-type-master",
3268                 _("Default Meter Type for Master Bus"),
3269                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_master),
3270                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_master)
3271                 );
3272         mtm->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
3273         mtm->add (MeterK20,     ArdourMeter::meter_type_string(MeterK20));
3274         mtm->add (MeterK14,     ArdourMeter::meter_type_string(MeterK14));
3275         mtm->add (MeterK12,     ArdourMeter::meter_type_string(MeterK12));
3276         mtm->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
3277         mtm->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
3278         mtm->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
3279         mtm->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
3280
3281         add_option (S_("Preferences|Metering"), mtm);
3282
3283
3284         ComboOption<MeterType>* mtb = new ComboOption<MeterType> (
3285                 "meter-type-bus",
3286                 _("Default Meter Type for Busses"),
3287                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_bus),
3288                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_bus)
3289                 );
3290         mtb->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
3291         mtb->add (MeterK20,     ArdourMeter::meter_type_string(MeterK20));
3292         mtb->add (MeterK14,     ArdourMeter::meter_type_string(MeterK14));
3293         mtb->add (MeterK12,     ArdourMeter::meter_type_string(MeterK12));
3294         mtb->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
3295         mtb->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
3296         mtb->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
3297         mtb->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
3298
3299         add_option (S_("Preferences|Metering"), mtb);
3300
3301         ComboOption<MeterType>* mtt = new ComboOption<MeterType> (
3302                 "meter-type-track",
3303                 _("Default Meter Type for Tracks"),
3304                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_track),
3305                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_track)
3306                 );
3307         mtt->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
3308         mtt->add (MeterPeak0dB, ArdourMeter::meter_type_string(MeterPeak0dB));
3309
3310         add_option (S_("Preferences|Metering"), mtt);
3311
3312
3313         Gtkmm2ext::UI::instance()->set_tip
3314                 (mpks->tip_widget(),
3315                  _("Specify the audio signal level in dBFS at and above which the meter-peak indicator will flash red."));
3316
3317         add_option (S_("Preferences|Metering"), mpks);
3318
3319         add_option (S_("Preferences|Metering"),
3320              new BoolOption (
3321                      "meter-style-led",
3322                      _("LED meter style"),
3323                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_style_led),
3324                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_style_led)
3325                      ));
3326
3327         add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Editor Meters")));
3328
3329         add_option (S_("Preferences|Metering"),
3330              new BoolOption (
3331                      "show-track-meters",
3332                      _("Show meters on tracks in the editor"),
3333                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_track_meters),
3334                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_track_meters)
3335                      ));
3336
3337         add_option (S_("Preferences|Metering"),
3338              new BoolOption (
3339                      "editor-stereo-only-meters",
3340                      _("Show at most stereo meters in the track-header"),
3341                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_editor_stereo_only_meters),
3342                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_editor_stereo_only_meters)
3343                      ));
3344
3345         add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Post Export Analysis")));
3346
3347         add_option (S_("Preferences|Metering"),
3348              new BoolOption (
3349                      "save-export-analysis-image",
3350                      _("Save loudness analysis as image file"),
3351                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_save_export_analysis_image),
3352                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_save_export_analysis_image)
3353                      ));
3354
3355         /* and now the theme manager */
3356
3357         ThemeManager* tm = manage (new ThemeManager);
3358         add_page (_("Theme"), *tm);
3359
3360         add_option (_("Theme/Colors"), new ColorThemeManager);
3361
3362         //trigger some parameter-changed messages which affect widget-visibility or -sensitivity
3363         parameter_changed ("send-ltc");
3364         parameter_changed ("sync-source");
3365         parameter_changed ("use-monitor-bus");
3366         parameter_changed ("open-gui-after-adding-plugin");
3367 }
3368
3369 void
3370 RCOptionEditor::parameter_changed (string const & p)
3371 {
3372         OptionEditor::parameter_changed (p);
3373
3374         if (p == "use-monitor-bus") {
3375                 bool const s = Config->get_use_monitor_bus ();
3376                 if (!s) {
3377                         /* we can't use this if we don't have a monitor bus */
3378                         Config->set_solo_control_is_listen_control (false);
3379                 }
3380                 _solo_control_is_listen_control->set_sensitive (s);
3381                 _listen_position->set_sensitive (s);
3382         } else if (p == "sync-source") {
3383                 _sync_source->set_sensitive (true);
3384                 if (_session) {
3385                         _sync_source->set_sensitive (!_session->config.get_external_sync());
3386                 }
3387                 switch(Config->get_sync_source()) {
3388                 case ARDOUR::MTC:
3389                 case ARDOUR::LTC:
3390                         _sync_genlock->set_sensitive (true);
3391                         _sync_framerate->set_sensitive (true);
3392                         _sync_source_2997->set_sensitive (true);
3393                         break;
3394                 default:
3395                         _sync_genlock->set_sensitive (false);
3396                         _sync_framerate->set_sensitive (false);
3397                         _sync_source_2997->set_sensitive (false);
3398                         break;
3399                 }
3400         } else if (p == "send-ltc") {
3401                 bool const s = Config->get_send_ltc ();
3402                 _ltc_send_continuously->set_sensitive (s);
3403                 _ltc_volume_slider->set_sensitive (s);
3404         } else if (p == "open-gui-after-adding-plugin" || p == "show-inline-display-by-default") {
3405 #if (defined LV2_SUPPORT && defined LV2_EXTENDED)
3406                 _plugin_prefer_inline->set_sensitive (UIConfiguration::instance().get_open_gui_after_adding_plugin() && UIConfiguration::instance().get_show_inline_display_by_default());
3407 #endif
3408         }
3409 }
3410
3411 void RCOptionEditor::ltc_generator_volume_changed () {
3412         _rc_config->set_ltc_output_volume (pow(10, _ltc_volume_adjustment->get_value() / 20));
3413 }
3414
3415 void RCOptionEditor::plugin_scan_refresh () {
3416         PluginManager::instance().refresh();
3417 }
3418
3419 void RCOptionEditor::clear_vst_cache () {
3420         PluginManager::instance().clear_vst_cache();
3421 }
3422
3423 void RCOptionEditor::clear_vst_blacklist () {
3424         PluginManager::instance().clear_vst_blacklist();
3425 }
3426
3427 void RCOptionEditor::clear_au_cache () {
3428         PluginManager::instance().clear_au_cache();
3429 }
3430
3431 void RCOptionEditor::clear_au_blacklist () {
3432         PluginManager::instance().clear_au_blacklist();
3433 }
3434
3435 void RCOptionEditor::edit_lxvst_path () {
3436         Glib::RefPtr<Gdk::Window> win = get_parent_window ();
3437         Gtkmm2ext::PathsDialog *pd = new Gtkmm2ext::PathsDialog (
3438                 *current_toplevel(), _("Set Linux VST Search Path"),
3439                 _rc_config->get_plugin_path_lxvst(),
3440                 PluginManager::instance().get_default_lxvst_path()
3441                 );
3442         ResponseType r = (ResponseType) pd->run ();
3443         pd->hide();
3444         if (r == RESPONSE_ACCEPT) {
3445                 _rc_config->set_plugin_path_lxvst(pd->get_serialized_paths());
3446         }
3447         delete pd;
3448 }
3449
3450 void RCOptionEditor::edit_vst_path () {
3451         Gtkmm2ext::PathsDialog *pd = new Gtkmm2ext::PathsDialog (
3452                 *current_toplevel(), _("Set Windows VST Search Path"),
3453                 _rc_config->get_plugin_path_vst(),
3454                 PluginManager::instance().get_default_windows_vst_path()
3455                 );
3456         ResponseType r = (ResponseType) pd->run ();
3457         pd->hide();
3458         if (r == RESPONSE_ACCEPT) {
3459                 _rc_config->set_plugin_path_vst(pd->get_serialized_paths());
3460         }
3461         delete pd;
3462 }
3463
3464
3465 void
3466 RCOptionEditor::populate_sync_options ()
3467 {
3468         vector<SyncSource> sync_opts = ARDOUR::get_available_sync_options ();
3469
3470         _sync_source->clear ();
3471
3472         for (vector<SyncSource>::iterator i = sync_opts.begin(); i != sync_opts.end(); ++i) {
3473                 _sync_source->add (*i, sync_source_to_string (*i));
3474         }
3475
3476         if (sync_opts.empty()) {
3477                 _sync_source->set_sensitive(false);
3478         } else {
3479                 if (std::find(sync_opts.begin(), sync_opts.end(), _rc_config->get_sync_source()) == sync_opts.end()) {
3480                         _rc_config->set_sync_source(sync_opts.front());
3481                 }
3482         }
3483
3484         parameter_changed ("sync-source");
3485 }
3486
3487 Gtk::Window*
3488 RCOptionEditor::use_own_window (bool and_fill_it)
3489 {
3490         bool new_window = !own_window();
3491
3492         Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
3493
3494         if (win && new_window) {
3495                 win->set_name ("PreferencesWindow");
3496                 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Preferences"), this);
3497         }
3498
3499         return win;
3500 }
3501
3502 XMLNode&
3503 RCOptionEditor::get_state ()
3504 {
3505         XMLNode* node = new XMLNode (X_("Preferences"));
3506         node->add_child_nocopy (Tabbable::get_state());
3507         return *node;
3508 }