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