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