push2:small logic fix for destructor, mostly to ensure that the track_mix layout...
[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         UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &RCOptionEditor::parameter_changed));
1864
1865         /* MISC */
1866
1867         uint32_t hwcpus = hardware_concurrency ();
1868         BoolOption* bo;
1869         BoolComboOption* bco;
1870
1871         if (hwcpus > 1) {
1872                 add_option (_("Misc"), new OptionEditorHeading (_("DSP CPU Utilization")));
1873
1874                 ComboOption<int32_t>* procs = new ComboOption<int32_t> (
1875                         "processor-usage",
1876                         _("Signal processing uses"),
1877                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_processor_usage),
1878                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_processor_usage)
1879                         );
1880
1881                 procs->add (-1, _("all but one processor"));
1882                 procs->add (0, _("all available processors"));
1883
1884                 for (uint32_t i = 1; i <= hwcpus; ++i) {
1885                         procs->add (i, string_compose (P_("%1 processor", "%1 processors", i), i));
1886                 }
1887
1888                 procs->set_note (string_compose (_("This setting will only take effect when %1 is restarted."), PROGRAM_NAME));
1889
1890                 add_option (_("Misc"), procs);
1891         }
1892
1893         add_option (_("Misc"), new OptionEditorHeading (S_("Options|Undo")));
1894
1895         add_option (_("Misc"), new UndoOptions (_rc_config));
1896
1897         add_option (_("Misc"),
1898              new BoolOption (
1899                      "verify-remove-last-capture",
1900                      _("Verify removal of last capture"),
1901                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_verify_remove_last_capture),
1902                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_verify_remove_last_capture)
1903                      ));
1904
1905         add_option (_("Misc"), new OptionEditorHeading (_("Session Management")));
1906
1907         add_option (_("Misc"),
1908              new BoolOption (
1909                      "periodic-safety-backups",
1910                      _("Make periodic backups of the session file"),
1911                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_periodic_safety_backups),
1912                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_periodic_safety_backups)
1913                      ));
1914
1915         add_option (_("Misc"),
1916              new BoolOption (
1917                      "only-copy-imported-files",
1918                      _("Always copy imported files"),
1919                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_only_copy_imported_files),
1920                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_only_copy_imported_files)
1921                      ));
1922
1923         add_option (_("Misc"), new DirectoryOption (
1924                             X_("default-session-parent-dir"),
1925                             _("Default folder for new sessions:"),
1926                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_default_session_parent_dir),
1927                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_default_session_parent_dir)
1928                             ));
1929
1930         add_option (_("Misc"),
1931              new SpinOption<uint32_t> (
1932                      "max-recent-sessions",
1933                      _("Maximum number of recent sessions"),
1934                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_max_recent_sessions),
1935                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_max_recent_sessions),
1936                      0, 1000, 1, 20
1937                      ));
1938
1939         add_option (_("Misc/Click"), new OptionEditorHeading (_("Click")));
1940
1941         add_option (_("Misc/Click"), new ClickOptions (_rc_config));
1942
1943         add_option (_("Misc/Click"),
1944              new FaderOption (
1945                      "click-gain",
1946                      _("Click gain level"),
1947                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_click_gain),
1948                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_click_gain)
1949                      ));
1950
1951         add_option (_("Misc"), new OptionEditorHeading (_("Automation")));
1952
1953         add_option (_("Misc"),
1954              new SpinOption<double> (
1955                      "automation-thinning-factor",
1956                      _("Thinning factor (larger value => less data)"),
1957                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_thinning_factor),
1958                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_thinning_factor),
1959                      0, 1000, 1, 20
1960                      ));
1961
1962         add_option (_("Misc"),
1963              new SpinOption<double> (
1964                      "automation-interval-msecs",
1965                      _("Automation sampling interval (milliseconds)"),
1966                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_interval_msecs),
1967                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_interval_msecs),
1968                      1, 1000, 1, 20
1969                      ));
1970
1971         /* TRANSPORT */
1972
1973         add_option (_("Transport"), new OptionEditorHeading (S_("Transport Options")));
1974
1975         BoolOption* tsf;
1976
1977         tsf = new BoolOption (
1978                      "latched-record-enable",
1979                      _("Keep record-enable engaged on stop"),
1980                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_latched_record_enable),
1981                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_latched_record_enable)
1982                      );
1983         // Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _(""));
1984         add_option (_("Transport"), tsf);
1985
1986         tsf = new BoolOption (
1987                      "loop-is-mode",
1988                      _("Play loop is a transport mode"),
1989                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_loop_is_mode),
1990                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_loop_is_mode)
1991                      );
1992         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(),
1993                                             (_("<b>When enabled</b> the loop button does not start playback but forces playback to always play the loop\n\n"
1994                                                "<b>When disabled</b> the loop button starts playing the loop, but stop then cancels loop playback")));
1995         add_option (_("Transport"), tsf);
1996
1997         tsf = new BoolOption (
1998                      "stop-recording-on-xrun",
1999                      _("Stop recording when an xrun occurs"),
2000                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_recording_on_xrun),
2001                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_recording_on_xrun)
2002                      );
2003         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(),
2004                                             string_compose (_("<b>When enabled</b> %1 will stop recording if an over- or underrun is detected by the audio engine"),
2005                                                             PROGRAM_NAME));
2006         add_option (_("Transport"), tsf);
2007
2008         tsf = new BoolOption (
2009                      "create-xrun-marker",
2010                      _("Create markers where xruns occur"),
2011                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_create_xrun_marker),
2012                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_create_xrun_marker)
2013                      );
2014         // Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _(""));
2015         add_option (_("Transport"), tsf);
2016
2017         tsf = new BoolOption (
2018                      "stop-at-session-end",
2019                      _("Stop at the end of the session"),
2020                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_at_session_end),
2021                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_at_session_end)
2022                      );
2023         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(),
2024                                             string_compose (_("<b>When enabled</b> if %1 is <b>not recording</b>, it will stop the transport "
2025                                                               "when it reaches the current session end marker\n\n"
2026                                                               "<b>When disabled</b> %1 will continue to roll past the session end marker at all times"),
2027                                                             PROGRAM_NAME));
2028         add_option (_("Transport"), tsf);
2029
2030         tsf = new BoolOption (
2031                      "seamless-loop",
2032                      _("Do seamless looping (not possible when slaved to MTC, LTC etc)"),
2033                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_seamless_loop),
2034                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_seamless_loop)
2035                      );
2036         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(),
2037                                             string_compose (_("<b>When enabled</b> this will loop by reading ahead and wrapping around at the loop point, "
2038                                                               "preventing any need to do a transport locate at the end of the loop\n\n"
2039                                                               "<b>When disabled</b> looping is done by locating back to the start of the loop when %1 reaches the end "
2040                                                               "which will often cause a small click or delay"), PROGRAM_NAME));
2041         add_option (_("Transport"), tsf);
2042
2043         tsf = new BoolOption (
2044                      "disable-disarm-during-roll",
2045                      _("Disable per-track record disarm while rolling"),
2046                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_disable_disarm_during_roll),
2047                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_disable_disarm_during_roll)
2048                      );
2049         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"));
2050         add_option (_("Transport"), tsf);
2051
2052         tsf = new BoolOption (
2053                      "quieten_at_speed",
2054                      _("12dB gain reduction during fast-forward and fast-rewind"),
2055                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_quieten_at_speed),
2056                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_quieten_at_speed)
2057                      );
2058         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _("This will reduce the unpleasant increase in perceived volume "
2059                                                    "that occurs when fast-forwarding or rewinding through some kinds of audio"));
2060         add_option (_("Transport"), tsf);
2061
2062         ComboOption<float>* psc = new ComboOption<float> (
2063                      "preroll-seconds",
2064                      _("Preroll"),
2065                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_preroll_seconds),
2066                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_preroll_seconds)
2067                      );
2068         Gtkmm2ext::UI::instance()->set_tip (psc->tip_widget(),
2069                                             (_("The amount of preroll (in seconds) to apply when <b>Play with Preroll</b> is initiated.\n\n"
2070                                                "If <b>Follow Edits</b> is enabled, the preroll is applied to the playhead position when a region is selected or trimmed.")));
2071         psc->add (0.0, _("0 (no pre-roll)"));
2072         psc->add (0.1, _("0.1 second"));
2073         psc->add (0.25, _("0.25 second"));
2074         psc->add (0.5, _("0.5 second"));
2075         psc->add (1.0, _("1.0 second"));
2076         psc->add (2.0, _("2.0 seconds"));
2077         add_option (_("Transport"), psc);
2078
2079         add_option (_("Transport/Sync"), new OptionEditorHeading (S_("Synchronization and Slave Options")));
2080
2081         _sync_source = new ComboOption<SyncSource> (
2082                 "sync-source",
2083                 _("External timecode source"),
2084                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_sync_source),
2085                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_sync_source)
2086                 );
2087
2088         add_option (_("Transport/Sync"), _sync_source);
2089
2090         _sync_framerate = new BoolOption (
2091                      "timecode-sync-frame-rate",
2092                      _("Match session video frame rate to external timecode"),
2093                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_sync_frame_rate),
2094                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_sync_frame_rate)
2095                      );
2096         Gtkmm2ext::UI::instance()->set_tip
2097                 (_sync_framerate->tip_widget(),
2098                  string_compose (_("This option controls the value of the video frame rate <i>while chasing</i> an external timecode source.\n\n"
2099                                    "<b>When enabled</b> the session video frame rate will be changed to match that of the selected external timecode source.\n\n"
2100                                    "<b>When disabled</b> the session video frame rate will not be changed to match that of the selected external timecode source."
2101                                    "Instead the frame rate indication in the main clock will flash red and %1 will convert between the external "
2102                                    "timecode standard and the session standard."), PROGRAM_NAME));
2103
2104         add_option (_("Transport/Sync"), _sync_framerate);
2105
2106         _sync_genlock = new BoolOption (
2107                 "timecode-source-is-synced",
2108                 _("Sync-lock timecode to clock (disable drift compensation)"),
2109                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_is_synced),
2110                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_is_synced)
2111                 );
2112         Gtkmm2ext::UI::instance()->set_tip
2113                 (_sync_genlock->tip_widget(),
2114                  string_compose (_("<b>When enabled</b> %1 will never varispeed when slaved to external timecode. "
2115                                    "Sync Lock indicates that the selected external timecode source shares clock-sync "
2116                                    "(Black &amp; Burst, Wordclock, etc) with the audio interface. "
2117                                    "This option disables drift compensation. The transport speed is fixed at 1.0. "
2118                                    "Vari-speed LTC will be ignored and cause drift."
2119                                    "\n\n"
2120                                    "<b>When disabled</b> %1 will compensate for potential drift, regardless if the "
2121                                    "timecode sources shares clock sync."
2122                                   ), PROGRAM_NAME));
2123
2124
2125         add_option (_("Transport/Sync"), _sync_genlock);
2126
2127         _sync_source_2997 = new BoolOption (
2128                 "timecode-source-2997",
2129                 _("Lock to 29.9700 fps instead of 30000/1001"),
2130                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_2997),
2131                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_2997)
2132                 );
2133         Gtkmm2ext::UI::instance()->set_tip
2134                 (_sync_source_2997->tip_widget(),
2135                  _("<b>When enabled</b> the external timecode source is assumed to use 29.97 fps instead of 30000/1001.\n"
2136                          "SMPTE 12M-1999 specifies 29.97df as 30000/1001. The spec further mentions that "
2137                          "drop-frame timecode has an accumulated error of -86ms over a 24-hour period.\n"
2138                          "Drop-frame timecode would compensate exactly for a NTSC color frame rate of 30 * 0.9990 (ie 29.970000). "
2139                          "That is not the actual rate. However, some vendors use that rate - despite it being against the specs - "
2140                          "because the variant of using exactly 29.97 fps has zero timecode drift.\n"
2141                          ));
2142
2143         add_option (_("Transport/Sync"), _sync_source_2997);
2144
2145         add_option (_("Transport/Sync"), new OptionEditorHeading (S_("LTC Reader")));
2146
2147         _ltc_port = new ComboStringOption (
2148                 "ltc-source-port",
2149                 _("LTC incoming port"),
2150                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_source_port),
2151                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_source_port)
2152                 );
2153
2154         vector<string> physical_inputs;
2155         physical_inputs.push_back (_("None"));
2156         AudioEngine::instance()->get_physical_inputs (DataType::AUDIO, physical_inputs);
2157         _ltc_port->set_popdown_strings (physical_inputs);
2158
2159         populate_sync_options ();
2160         AudioEngine::instance()->Running.connect (engine_started_connection, MISSING_INVALIDATOR, boost::bind (&RCOptionEditor::populate_sync_options, this), gui_context());
2161
2162         add_option (_("Transport/Sync"), _ltc_port);
2163
2164         // TODO; rather disable this button than not compile it..
2165         add_option (_("Transport/Sync"), new OptionEditorHeading (S_("LTC Generator")));
2166
2167         add_option (_("Transport/Sync"),
2168                     new BoolOption (
2169                             "send-ltc",
2170                             _("Enable LTC generator"),
2171                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_ltc),
2172                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_ltc)
2173                             ));
2174
2175         _ltc_send_continuously = new BoolOption (
2176                             "ltc-send-continuously",
2177                             _("Send LTC while stopped"),
2178                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_send_continuously),
2179                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_send_continuously)
2180                             );
2181         Gtkmm2ext::UI::instance()->set_tip
2182                 (_ltc_send_continuously->tip_widget(),
2183                  string_compose (_("<b>When enabled</b> %1 will continue to send LTC information even when the transport (playhead) is not moving"), PROGRAM_NAME));
2184         add_option (_("Transport"), _ltc_send_continuously);
2185
2186         _ltc_volume_adjustment = new Gtk::Adjustment(-18, -50, 0, .5, 5);
2187         _ltc_volume_adjustment->set_value (20 * log10(_rc_config->get_ltc_output_volume()));
2188         _ltc_volume_adjustment->signal_value_changed().connect (sigc::mem_fun (*this, &RCOptionEditor::ltc_generator_volume_changed));
2189         _ltc_volume_slider = new HSliderOption("ltcvol", _("LTC generator level"), *_ltc_volume_adjustment);
2190
2191         Gtkmm2ext::UI::instance()->set_tip
2192                 (_ltc_volume_slider->tip_widget(),
2193                  _("Specify the Peak Volume of the generated LTC signal in dBFS. A good value is  0dBu ^= -18dBFS in an EBU calibrated system"));
2194
2195         add_option (_("Transport/Sync"), _ltc_volume_slider);
2196
2197         /* EDITOR */
2198
2199         add_option (_("Editor"),
2200              new BoolOption (
2201                      "rubberbanding-snaps-to-grid",
2202                      _("Make rubberband selection rectangle snap to the grid"),
2203                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_rubberbanding_snaps_to_grid),
2204                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_rubberbanding_snaps_to_grid)
2205                      ));
2206
2207         bo = new BoolOption (
2208                      "name-new-markers",
2209                      _("Name new markers"),
2210                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_name_new_markers),
2211                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_name_new_markers)
2212                 );
2213         add_option (_("Editor"), bo);
2214         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."
2215                                                                 "\n\nYou can always rename markers by right-clicking on them"));
2216
2217         add_option (S_("Editor"),
2218              new BoolOption (
2219                      "draggable-playhead",
2220                      _("Allow dragging of playhead"),
2221                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_draggable_playhead),
2222                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_draggable_playhead)
2223                      ));
2224
2225         add_option (_("Editor"),
2226              new BoolOption (
2227                      "show-editor-meter",
2228                      _("Display master-meter in the toolbar"),
2229                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_editor_meter),
2230                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_editor_meter)
2231                      ));
2232
2233 if (!Profile->get_mixbus()) {
2234         add_option (_("Editor"),
2235                     new BoolOption (
2236                             "show-zoom-tools",
2237                             _("Show zoom toolbar (if torn off)"),
2238                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_zoom_tools),
2239                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_zoom_tools)
2240                             ));
2241
2242         add_option (_("Editor"),
2243                     new BoolOption (
2244                             "use-mouse-position-as-zoom-focus-on-scroll",
2245                             _("Always use mouse cursor position as zoom focus when zooming using mouse scroll wheel"),
2246                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_mouse_position_as_zoom_focus_on_scroll),
2247                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_mouse_position_as_zoom_focus_on_scroll)
2248                             ));
2249 }  // !mixbus
2250
2251         add_option (_("Editor"),
2252                     new BoolOption (
2253                             "update-editor-during-summary-drag",
2254                             _("Update editor window during drags of the summary"),
2255                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_update_editor_during_summary_drag),
2256                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_update_editor_during_summary_drag)
2257                             ));
2258
2259         add_option (_("Editor"),
2260             new BoolOption (
2261                     "autoscroll-editor",
2262                     _("Auto-scroll editor window when dragging near its edges"),
2263                     sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_autoscroll_editor),
2264                     sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_autoscroll_editor)
2265                     ));
2266
2267         add_option (_("Editor"),
2268              new BoolComboOption (
2269                      "show-region-gain-envelopes",
2270                      _("Show gain envelopes in audio regions"),
2271                      _("in all modes"),
2272                      _("only in Draw and Internal Edit modes"),
2273                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_region_gain),
2274                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_region_gain)
2275                      ));
2276
2277         add_option (_("Editor"), new OptionEditorHeading (_("Editor Behavior")));
2278
2279         add_option (_("Editor"),
2280              new BoolOption (
2281                      "automation-follows-regions",
2282                      _("Move relevant automation when audio regions are moved"),
2283                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_follows_regions),
2284                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_follows_regions)
2285                      ));
2286
2287         ComboOption<FadeShape>* fadeshape = new ComboOption<FadeShape> (
2288                         "default-fade-shape",
2289                         _("Default fade shape"),
2290                         sigc::mem_fun (*_rc_config,
2291                                 &RCConfiguration::get_default_fade_shape),
2292                         sigc::mem_fun (*_rc_config,
2293                                 &RCConfiguration::set_default_fade_shape)
2294                         );
2295
2296         fadeshape->add (FadeLinear,
2297                         _("Linear (for highly correlated material)"));
2298         fadeshape->add (FadeConstantPower, _("Constant power"));
2299         fadeshape->add (FadeSymmetric, _("Symmetric"));
2300         fadeshape->add (FadeSlow, _("Slow"));
2301         fadeshape->add (FadeFast, _("Fast"));
2302
2303         add_option (_("Editor"), fadeshape);
2304
2305
2306         bco = new BoolComboOption (
2307                      "use-overlap-equivalency",
2308                      _("Regions in active edit groups are edited together"),
2309                      _("whenever they overlap in time"),
2310                      _("only if they have identical length, position and origin"),
2311                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_use_overlap_equivalency),
2312                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_use_overlap_equivalency)
2313                      );
2314
2315         add_option (_("Editor"), bco);
2316
2317         ComboOption<LayerModel>* lm = new ComboOption<LayerModel> (
2318                 "layer-model",
2319                 _("Layering model"),
2320                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_layer_model),
2321                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_layer_model)
2322                 );
2323
2324         lm->add (LaterHigher, _("later is higher"));
2325         lm->add (Manual, _("manual layering"));
2326         add_option (_("Editor"), lm);
2327
2328         ComboOption<RegionSelectionAfterSplit> *rsas = new ComboOption<RegionSelectionAfterSplit> (
2329                     "region-selection-after-split",
2330                     _("After splitting selected regions, select"),
2331                     sigc::mem_fun (*_rc_config, &RCConfiguration::get_region_selection_after_split),
2332                     sigc::mem_fun (*_rc_config, &RCConfiguration::set_region_selection_after_split));
2333
2334         // TODO: decide which of these modes are really useful
2335         rsas->add(None, _("no regions"));
2336         // rsas->add(NewlyCreatedLeft, _("newly-created regions before the split"));
2337         // rsas->add(NewlyCreatedRight, _("newly-created regions after the split"));
2338         rsas->add(NewlyCreatedBoth, _("newly-created regions"));
2339         // rsas->add(Existing, _("unmodified regions in the existing selection"));
2340         // rsas->add(ExistingNewlyCreatedLeft, _("existing selection and newly-created regions before the split"));
2341         // rsas->add(ExistingNewlyCreatedRight, _("existing selection and newly-created regions after the split"));
2342         rsas->add(ExistingNewlyCreatedBoth, _("existing selection and newly-created regions"));
2343
2344         add_option (_("Editor"), rsas);
2345
2346         add_option (_("Editor/Waveforms"), new OptionEditorHeading (_("Waveforms")));
2347
2348 if (!Profile->get_mixbus()) {
2349         add_option (_("Editor/Waveforms"),
2350              new BoolOption (
2351                      "show-waveforms",
2352                      _("Show waveforms in regions"),
2353                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveforms),
2354                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveforms)
2355                      ));
2356 }  // !mixbus
2357
2358         add_option (_("Editor/Waveforms"),
2359              new BoolOption (
2360                      "show-waveforms-while-recording",
2361                      _("Show waveforms for audio while it is being recorded"),
2362                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveforms_while_recording),
2363                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveforms_while_recording)
2364                      ));
2365
2366         ComboOption<WaveformScale>* wfs = new ComboOption<WaveformScale> (
2367                 "waveform-scale",
2368                 _("Waveform scale"),
2369                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_scale),
2370                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_scale)
2371                 );
2372
2373         wfs->add (Linear, _("linear"));
2374         wfs->add (Logarithmic, _("logarithmic"));
2375
2376         add_option (_("Editor/Waveforms"), wfs);
2377
2378         ComboOption<WaveformShape>* wfsh = new ComboOption<WaveformShape> (
2379                 "waveform-shape",
2380                 _("Waveform shape"),
2381                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_shape),
2382                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_shape)
2383                 );
2384
2385         wfsh->add (Traditional, _("traditional"));
2386         wfsh->add (Rectified, _("rectified"));
2387
2388         add_option (_("Editor/Waveforms"), wfsh);
2389
2390         add_option (_("Editor/Waveforms"), new ClipLevelOptions ());
2391
2392
2393         /* AUDIO */
2394
2395         add_option (_("Audio"), new OptionEditorHeading (_("Buffering")));
2396
2397         add_option (_("Audio"), new BufferingOptions (_rc_config));
2398
2399         add_option (_("Audio"), new OptionEditorHeading (_("Monitoring")));
2400
2401         ComboOption<MonitorModel>* mm = new ComboOption<MonitorModel> (
2402                 "monitoring-model",
2403                 _("Record monitoring handled by"),
2404                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_monitoring_model),
2405                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_monitoring_model)
2406                 );
2407
2408         if (AudioEngine::instance()->port_engine().can_monitor_input()) {
2409                 mm->add (HardwareMonitoring, _("via Audio Driver"));
2410         }
2411
2412         string prog (PROGRAM_NAME);
2413         boost::algorithm::to_lower (prog);
2414         mm->add (SoftwareMonitoring, string_compose (_("%1"), prog));
2415         mm->add (ExternalMonitoring, _("audio hardware"));
2416
2417         add_option (_("Audio"), mm);
2418
2419         add_option (_("Audio"),
2420              new BoolOption (
2421                      "tape-machine-mode",
2422                      _("Tape machine mode"),
2423                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_tape_machine_mode),
2424                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_tape_machine_mode)
2425                      ));
2426
2427         add_option (_("Audio"), new OptionEditorHeading (_("Connection of tracks and busses")));
2428 if (!Profile->get_mixbus()) {
2429
2430         add_option (_("Audio"),
2431                     new BoolOption (
2432                             "auto-connect-standard-busses",
2433                             _("Auto-connect master/monitor busses"),
2434                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_connect_standard_busses),
2435                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_connect_standard_busses)
2436                             ));
2437
2438         ComboOption<AutoConnectOption>* iac = new ComboOption<AutoConnectOption> (
2439                 "input-auto-connect",
2440                 _("Connect track inputs"),
2441                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_input_auto_connect),
2442                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_input_auto_connect)
2443                 );
2444
2445         iac->add (AutoConnectPhysical, _("automatically to physical inputs"));
2446         iac->add (ManualConnect, _("manually"));
2447
2448         add_option (_("Audio"), iac);
2449
2450         ComboOption<AutoConnectOption>* oac = new ComboOption<AutoConnectOption> (
2451                 "output-auto-connect",
2452                 _("Connect track and bus outputs"),
2453                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_output_auto_connect),
2454                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_output_auto_connect)
2455                 );
2456
2457         oac->add (AutoConnectPhysical, _("automatically to physical outputs"));
2458         oac->add (AutoConnectMaster, _("automatically to master bus"));
2459         oac->add (ManualConnect, _("manually"));
2460
2461         add_option (_("Audio"), oac);
2462
2463         bo = new BoolOption (
2464                         "strict-io",
2465                         _("Use 'Strict-I/O' for new tracks or Busses"),
2466                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_strict_io),
2467                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_strict_io)
2468                         );
2469
2470         add_option (_("Audio"), bo);
2471         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2472                         _("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."));
2473
2474 }  // !mixbus
2475
2476         add_option (_("Audio"), new OptionEditorHeading (_("Denormals")));
2477
2478         add_option (_("Audio"),
2479              new BoolOption (
2480                      "denormal-protection",
2481                      _("Use DC bias to protect against denormals"),
2482                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_protection),
2483                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_protection)
2484                      ));
2485
2486         ComboOption<DenormalModel>* dm = new ComboOption<DenormalModel> (
2487                 "denormal-model",
2488                 _("Processor handling"),
2489                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_model),
2490                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_model)
2491                 );
2492
2493         int dmsize = 1;
2494         dm->add (DenormalNone, _("no processor handling"));
2495
2496         FPU* fpu = FPU::instance();
2497
2498         if (fpu->has_flush_to_zero()) {
2499                 ++dmsize;
2500                 dm->add (DenormalFTZ, _("use FlushToZero"));
2501         } else if (_rc_config->get_denormal_model() == DenormalFTZ) {
2502                 _rc_config->set_denormal_model(DenormalNone);
2503         }
2504
2505         if (fpu->has_denormals_are_zero()) {
2506                 ++dmsize;
2507                 dm->add (DenormalDAZ, _("use DenormalsAreZero"));
2508         } else if (_rc_config->get_denormal_model() == DenormalDAZ) {
2509                 _rc_config->set_denormal_model(DenormalNone);
2510         }
2511
2512         if (fpu->has_flush_to_zero() && fpu->has_denormals_are_zero()) {
2513                 ++dmsize;
2514                 dm->add (DenormalFTZDAZ, _("use FlushToZero and DenormalsAreZero"));
2515         } else if (_rc_config->get_denormal_model() == DenormalFTZDAZ) {
2516                 _rc_config->set_denormal_model(DenormalNone);
2517         }
2518
2519         if (dmsize == 1) {
2520                 dm->set_sensitive(false);
2521         }
2522
2523         add_option (_("Audio"), dm);
2524
2525         add_option (_("Audio"), new OptionEditorHeading (_("Regions")));
2526
2527         add_option (_("Audio"),
2528              new BoolOption (
2529                      "auto-analyse-audio",
2530                      _("Enable automatic analysis of audio"),
2531                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_analyse_audio),
2532                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_analyse_audio)
2533                      ));
2534
2535         add_option (_("Audio"),
2536              new BoolOption (
2537                      "replicate-missing-region-channels",
2538                      _("Replicate missing region channels"),
2539                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_replicate_missing_region_channels),
2540                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_replicate_missing_region_channels)
2541                      ));
2542
2543         /* SOLO AND MUTE */
2544
2545         add_option (_("Solo & mute"), new OptionEditorHeading (_("Solo")));
2546
2547         _solo_control_is_listen_control = new BoolOption (
2548                 "solo-control-is-listen-control",
2549                 _("Solo controls are Listen controls"),
2550                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_control_is_listen_control),
2551                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_control_is_listen_control)
2552                 );
2553
2554         add_option (_("Solo & mute"), _solo_control_is_listen_control);
2555
2556         add_option (_("Solo & mute"),
2557              new BoolOption (
2558                      "exclusive-solo",
2559                      _("Exclusive solo"),
2560                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_exclusive_solo),
2561                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_exclusive_solo)
2562                      ));
2563
2564         add_option (_("Solo & mute"),
2565              new BoolOption (
2566                      "show-solo-mutes",
2567                      _("Show solo muting"),
2568                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_show_solo_mutes),
2569                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_solo_mutes)
2570                      ));
2571
2572         add_option (_("Solo & mute"),
2573              new BoolOption (
2574                      "solo-mute-override",
2575                      _("Soloing overrides muting"),
2576                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_override),
2577                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_override)
2578                      ));
2579
2580         add_option (_("Solo & mute"),
2581              new FaderOption (
2582                      "solo-mute-gain",
2583                      _("Solo-in-place mute cut (dB)"),
2584                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_gain),
2585                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_gain)
2586                      ));
2587
2588         _listen_position = new ComboOption<ListenPosition> (
2589                 "listen-position",
2590                 _("Listen Position"),
2591                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_listen_position),
2592                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_listen_position)
2593                 );
2594
2595         _listen_position->add (AfterFaderListen, _("after-fader (AFL)"));
2596         _listen_position->add (PreFaderListen, _("pre-fader (PFL)"));
2597
2598         add_option (_("Solo & mute"), _listen_position);
2599
2600         ComboOption<PFLPosition>* pp = new ComboOption<PFLPosition> (
2601                 "pfl-position",
2602                 _("PFL signals come from"),
2603                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_pfl_position),
2604                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_pfl_position)
2605                 );
2606
2607         pp->add (PFLFromBeforeProcessors, _("before pre-fader processors"));
2608         pp->add (PFLFromAfterProcessors, _("pre-fader but after pre-fader processors"));
2609
2610         add_option (_("Solo & mute"), pp);
2611
2612         ComboOption<AFLPosition>* pa = new ComboOption<AFLPosition> (
2613                 "afl-position",
2614                 _("AFL signals come from"),
2615                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_afl_position),
2616                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_afl_position)
2617                 );
2618
2619         pa->add (AFLFromBeforeProcessors, _("immediately post-fader"));
2620         pa->add (AFLFromAfterProcessors, _("after post-fader processors (before pan)"));
2621
2622         add_option (_("Solo & mute"), pa);
2623
2624         add_option (_("Solo & mute"), new OptionEditorHeading (_("Default track / bus muting options")));
2625
2626         add_option (_("Solo & mute"),
2627              new BoolOption (
2628                      "mute-affects-pre-fader",
2629                      _("Mute affects pre-fader sends"),
2630                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_pre_fader),
2631                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_pre_fader)
2632                      ));
2633
2634         add_option (_("Solo & mute"),
2635              new BoolOption (
2636                      "mute-affects-post-fader",
2637                      _("Mute affects post-fader sends"),
2638                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_post_fader),
2639                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_post_fader)
2640                      ));
2641
2642         add_option (_("Solo & mute"),
2643              new BoolOption (
2644                      "mute-affects-control-outs",
2645                      _("Mute affects control outputs"),
2646                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_control_outs),
2647                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_control_outs)
2648                      ));
2649
2650         add_option (_("Solo & mute"),
2651              new BoolOption (
2652                      "mute-affects-main-outs",
2653                      _("Mute affects main outputs"),
2654                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_main_outs),
2655                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_main_outs)
2656                      ));
2657
2658
2659 if (!ARDOUR::Profile->get_mixbus()) {
2660         add_option (_("Solo & mute"), new OptionEditorHeading (_("Send Routing")));
2661         add_option (_("Solo & mute"),
2662              new BoolOption (
2663                      "link-send-and-route-panner",
2664                      _("Link panners of Aux and External Sends with main panner by default"),
2665                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_link_send_and_route_panner),
2666                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_link_send_and_route_panner)
2667                      ));
2668 }
2669
2670         add_option (_("MIDI"), new OptionEditorHeading (_("MIDI Preferences")));
2671
2672         add_option (_("MIDI"),
2673                     new SpinOption<float> (
2674                             "midi-readahead",
2675                             _("MIDI read-ahead time (seconds)"),
2676                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_readahead),
2677                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_readahead),
2678                             0.1, 10, 0.1, 1,
2679                             "", 1.0, 1
2680                             ));
2681
2682         add_option (_("MIDI"),
2683              new SpinOption<int32_t> (
2684                      "initial-program-change",
2685                      _("Initial program change"),
2686                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_initial_program_change),
2687                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_initial_program_change),
2688                      -1, 65536, 1, 10
2689                      ));
2690
2691         add_option (_("MIDI"),
2692                     new BoolOption (
2693                             "display-first-midi-bank-as-zero",
2694                             _("Display first MIDI bank/program as 0"),
2695                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_first_midi_bank_is_zero),
2696                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_first_midi_bank_is_zero)
2697                             ));
2698
2699         add_option (_("MIDI"),
2700              new BoolOption (
2701                      "never-display-periodic-midi",
2702                      _("Never display periodic MIDI messages (MTC, MIDI Clock)"),
2703                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_never_display_periodic_midi),
2704                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_never_display_periodic_midi)
2705                      ));
2706
2707         add_option (_("MIDI"),
2708              new BoolOption (
2709                      "sound-midi-notes",
2710                      _("Sound MIDI notes as they are selected in the editor"),
2711                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_sound_midi_notes),
2712                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_sound_midi_notes)
2713                      ));
2714
2715         add_option (_("MIDI"),
2716                     new BoolOption (
2717                             "midi-feedback",
2718                             _("Send MIDI control feedback"),
2719                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_feedback),
2720                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_feedback)
2721                             ));
2722
2723         add_option (_("MIDI/Sync"), new OptionEditorHeading (_("MIDI Clock")));
2724
2725         add_option (_("MIDI/Sync"),
2726                     new BoolOption (
2727                             "send-midi-clock",
2728                             _("Send MIDI Clock"),
2729                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_midi_clock),
2730                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_midi_clock)
2731                             ));
2732
2733         add_option (_("MIDI/Sync"), new OptionEditorHeading (_("MIDI Time Code (MTC)")));
2734
2735         add_option (_("MIDI/Sync"),
2736                     new BoolOption (
2737                             "send-mtc",
2738                             _("Send MIDI Time Code"),
2739                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mtc),
2740                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mtc)
2741                             ));
2742
2743         add_option (_("MIDI/Sync"),
2744                     new SpinOption<int> (
2745                             "mtc-qf-speed-tolerance",
2746                             _("Percentage either side of normal transport speed to transmit MTC"),
2747                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mtc_qf_speed_tolerance),
2748                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mtc_qf_speed_tolerance),
2749                             0, 20, 1, 5
2750                             ));
2751
2752         add_option (_("MIDI/Sync"), new OptionEditorHeading (_("Midi Machine Control (MMC)")));
2753
2754         add_option (_("MIDI/Sync"),
2755                     new BoolOption (
2756                             "mmc-control",
2757                             _("Obey MIDI Machine Control commands"),
2758                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_control),
2759                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_control)
2760                             ));
2761
2762         add_option (_("MIDI/Sync"),
2763                     new BoolOption (
2764                             "send-mmc",
2765                             _("Send MIDI Machine Control commands"),
2766                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mmc),
2767                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mmc)
2768                             ));
2769
2770         add_option (_("MIDI/Sync"),
2771              new SpinOption<uint8_t> (
2772                      "mmc-receive-device-id",
2773                      _("Inbound MMC device ID"),
2774                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_receive_device_id),
2775                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_receive_device_id),
2776                      0, 128, 1, 10
2777                      ));
2778
2779         add_option (_("MIDI/Sync"),
2780              new SpinOption<uint8_t> (
2781                      "mmc-send-device-id",
2782                      _("Outbound MMC device ID"),
2783                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_send_device_id),
2784                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_send_device_id),
2785                      0, 128, 1, 10
2786                      ));
2787
2788         add_option (_("MIDI"), new OptionEditorHeading (_("Midi Audition")));
2789
2790         ComboOption<std::string>* audition_synth = new ComboOption<std::string> (
2791                 "midi-audition-synth-uri",
2792                 _("Midi Audition Synth (LV2)"),
2793                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_audition_synth_uri),
2794                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_audition_synth_uri)
2795                 );
2796
2797         audition_synth->add(X_(""), _("None"));
2798         PluginInfoList all_plugs;
2799         PluginManager& manager (PluginManager::instance());
2800 #ifdef LV2_SUPPORT
2801         all_plugs.insert (all_plugs.end(), manager.lv2_plugin_info().begin(), manager.lv2_plugin_info().end());
2802
2803         for (PluginInfoList::const_iterator i = all_plugs.begin(); i != all_plugs.end(); ++i) {
2804                 if (manager.get_status (*i) == PluginManager::Hidden) continue;
2805                 if (!(*i)->is_instrument()) continue;
2806                 if ((*i)->type != ARDOUR::LV2) continue;
2807                 audition_synth->add((*i)->unique_id, (*i)->name);
2808         }
2809 #endif
2810
2811         add_option (_("MIDI"), audition_synth);
2812
2813         /* USER INTERACTION */
2814
2815         if (
2816 #ifdef PLATFORM_WINDOWS
2817                         true
2818 #else
2819                         getenv ("ARDOUR_BUNDLED")
2820 #endif
2821            )
2822         {
2823                 add_option (_("User interaction"),
2824                             new BoolOption (
2825                                     "enable-translation",
2826                                     string_compose (_("Use translations of %1 messages\n"
2827                                                       "   <i>(requires a restart of %1 to take effect)</i>\n"
2828                                                       "   <i>(if available for your language preferences)</i>"), PROGRAM_NAME),
2829                                     sigc::ptr_fun (ARDOUR::translations_are_enabled),
2830                                     sigc::ptr_fun (ARDOUR::set_translations_enabled)));
2831         }
2832
2833         add_option (_("User interaction"), new OptionEditorHeading (_("Keyboard")));
2834
2835         add_option (_("User interaction"), new KeyboardOptions);
2836
2837         /* Control Surfaces */
2838
2839         add_option (_("Control Surfaces"), new ControlSurfacesOptions);
2840
2841         /* VIDEO Timeline */
2842         add_option (_("Video"), new VideoTimelineOptions (_rc_config));
2843
2844 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined AUDIOUNIT_SUPPORT)
2845         add_option (_("Plugins"),
2846                         new RcActionButton (_("Scan for Plugins"),
2847                                 sigc::mem_fun (*this, &RCOptionEditor::plugin_scan_refresh)));
2848
2849 #endif
2850
2851         add_option (_("Plugins"), new OptionEditorHeading (_("General")));
2852
2853 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined AUDIOUNIT_SUPPORT)
2854         bo = new BoolOption (
2855                         "show-plugin-scan-window",
2856                         _("Always Display Plugin Scan Progress"),
2857                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_plugin_scan_window),
2858                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_plugin_scan_window)
2859                         );
2860         add_option (_("Plugins"), bo);
2861         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2862                         _("<b>When enabled</b> a popup window showing plugin scan progress is displayed for indexing (cache load) and discovery (detect new plugins)"));
2863 #endif
2864
2865         bo = new BoolOption (
2866                 "plugins-stop-with-transport",
2867                 _("Silence plugins when the transport is stopped"),
2868                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugins_stop_with_transport),
2869                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_plugins_stop_with_transport)
2870                 );
2871         add_option (_("Plugins"), bo);
2872         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2873                                             _("<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."));
2874
2875         bo = new BoolOption (
2876                 "new-plugins-active",
2877                         _("Make new plugins active"),
2878                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_new_plugins_active),
2879                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_new_plugins_active)
2880                         );
2881         add_option (_("Plugins"), bo);
2882         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2883                                             _("<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"));
2884
2885 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
2886         add_option (_("Plugins/VST"), new OptionEditorHeading (_("VST")));
2887         add_option (_("Plugins/VST"),
2888                         new RcActionButton (_("Scan for Plugins"),
2889                                 sigc::mem_fun (*this, &RCOptionEditor::plugin_scan_refresh)));
2890
2891         bo = new BoolOption (
2892                         "discover-vst-on-start",
2893                         _("Scan for [new] VST Plugins on Application Start"),
2894                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_discover_vst_on_start),
2895                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_discover_vst_on_start)
2896                         );
2897         add_option (_("Plugins/VST"), bo);
2898         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2899                                             _("<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"));
2900
2901 #ifdef WINDOWS_VST_SUPPORT
2902         // currently verbose logging is only implemented for Windows VST.
2903         bo = new BoolOption (
2904                         "verbose-plugin-scan",
2905                         _("Verbose Plugin Scan"),
2906                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_verbose_plugin_scan),
2907                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_verbose_plugin_scan)
2908                         );
2909         add_option (_("Plugins/VST"), bo);
2910         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2911                                             _("<b>When enabled</b> additional information for every plugin is added to the Log Window."));
2912 #endif
2913
2914         add_option (_("Plugins/VST"), new VstTimeOutSliderOption (_rc_config));
2915
2916         add_option (_("Plugins/VST"),
2917                         new RcActionButton (_("Clear"),
2918                                 sigc::mem_fun (*this, &RCOptionEditor::clear_vst_cache),
2919                                 _("VST Cache:")));
2920
2921         add_option (_("Plugins/VST"),
2922                         new RcActionButton (_("Clear"),
2923                                 sigc::mem_fun (*this, &RCOptionEditor::clear_vst_blacklist),
2924                                 _("VST Blacklist:")));
2925 #endif
2926
2927 #ifdef LXVST_SUPPORT
2928         add_option (_("Plugins/VST"),
2929                         new RcActionButton (_("Edit"),
2930                                 sigc::mem_fun (*this, &RCOptionEditor::edit_lxvst_path),
2931                         _("Linux VST Path:")));
2932
2933         add_option (_("Plugins/VST"),
2934                         new RcConfigDisplay (
2935                                 "plugin-path-lxvst",
2936                                 _("Path:"),
2937                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugin_path_lxvst),
2938                                 0));
2939 #endif
2940
2941 #ifdef WINDOWS_VST_SUPPORT
2942         add_option (_("Plugins/VST"),
2943                         new RcActionButton (_("Edit"),
2944                                 sigc::mem_fun (*this, &RCOptionEditor::edit_vst_path),
2945                         _("Windows VST Path:")));
2946         add_option (_("Plugins"),
2947                         new RcConfigDisplay (
2948                                 "plugin-path-vst",
2949                                 _("Path:"),
2950                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugin_path_vst),
2951                                 ';'));
2952 #endif
2953
2954 #ifdef AUDIOUNIT_SUPPORT
2955
2956         add_option (_("Plugins/Audio Unit"), new OptionEditorHeading (_("Audio Unit")));
2957         add_option (_("Plugins/Audio Unit"),
2958                         new RcActionButton (_("Scan for Plugins"),
2959                                 sigc::mem_fun (*this, &RCOptionEditor::plugin_scan_refresh)));
2960
2961         bo = new BoolOption (
2962                         "discover-audio-units",
2963                         _("Scan for AudioUnit Plugins on Application Start"),
2964                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_discover_audio_units),
2965                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_discover_audio_units)
2966                         );
2967         add_option (_("Plugins"), bo);
2968         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2969                                             _("<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."));
2970
2971         add_option (_("Plugins/Audio Unit"),
2972                         new RcActionButton (_("Clear"),
2973                                 sigc::mem_fun (*this, &RCOptionEditor::clear_au_cache),
2974                                 _("AU Cache:")));
2975
2976         add_option (_("Plugins/Audio Unit"),
2977                         new RcActionButton (_("Clear"),
2978                                 sigc::mem_fun (*this, &RCOptionEditor::clear_au_blacklist),
2979                                 _("AU Blacklist:")));
2980 #endif
2981
2982 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined AUDIOUNIT_SUPPORT || defined HAVE_LV2)
2983         add_option (_("Plugins"), new OptionEditorHeading (_("Plugin GUI")));
2984         add_option (_("Plugins"),
2985              new BoolOption (
2986                      "open-gui-after-adding-plugin",
2987                      _("Automatically open the plugin GUI when adding a new plugin"),
2988                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_open_gui_after_adding_plugin),
2989                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_open_gui_after_adding_plugin)
2990                      ));
2991
2992 #if (defined LV2_SUPPORT && defined LV2_EXTENDED)
2993         add_option (_("Plugins"),
2994              new BoolOption (
2995                      "show-inline-display-by-default",
2996                      _("Show Plugin Inline Display on Mixerstrip by default"),
2997                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_inline_display_by_default),
2998                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_inline_display_by_default)
2999                      ));
3000
3001         _plugin_prefer_inline = new BoolOption (
3002                         "prefer-inline-over-gui",
3003                         _("Don't automatically open the plugin GUI when the plugin has an inline display mode"),
3004                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_prefer_inline_over_gui),
3005                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_prefer_inline_over_gui)
3006                         );
3007         add_option (_("Plugins"), _plugin_prefer_inline);
3008 #endif
3009
3010         add_option (_("Plugins"), new OptionEditorHeading (_("Instrument")));
3011
3012         bo = new BoolOption (
3013                         "ask-replace-instrument",
3014                         _("Ask to replace existing instrument plugin"),
3015                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_ask_replace_instrument),
3016                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_ask_replace_instrument)
3017                         );
3018         add_option (_("Plugins"), bo);
3019
3020         bo = new BoolOption (
3021                         "ask-setup_instrument",
3022                         _("Interactively configure instrument plugins on insert"),
3023                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_ask_setup_instrument),
3024                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_ask_setup_instrument)
3025                         );
3026         add_option (_("Plugins"), bo);
3027         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3028                         _("<b>When enabled</b> show a dialog to select instrument channel configuration before adding a multichannel plugin."));
3029
3030 #endif
3031
3032         /* INTERFACE */
3033
3034 #ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
3035         BoolOption* bgc = new BoolOption (
3036                 "cairo-image-surface",
3037                 _("Disable Graphics Hardware Acceleration (requires restart)"),
3038                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_cairo_image_surface),
3039                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_cairo_image_surface)
3040                 );
3041
3042         Gtkmm2ext::UI::instance()->set_tip (bgc->tip_widget(), string_compose (
3043                                 _("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));
3044         add_option (S_("Preferences|GUI"), bgc);
3045 #endif
3046
3047 #ifdef CAIRO_SUPPORTS_FORCE_BUGGY_GRADIENTS_ENVIRONMENT_VARIABLE
3048         BoolOption* bgo = new BoolOption (
3049                 "buggy-gradients",
3050                 _("Possibly improve slow graphical performance (requires restart)"),
3051                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_buggy_gradients),
3052                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_buggy_gradients)
3053                 );
3054
3055         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));
3056         add_option (S_("Preferences|GUI"), bgo);
3057 #endif
3058
3059         add_option (S_("Preferences|GUI"),
3060              new BoolOption (
3061                      "use-wm-visibility",
3062                      _("Use Window Manager/Desktop visibility information"),
3063                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_wm_visibility),
3064                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_wm_visibility)
3065                      ));
3066
3067         add_option (S_("Preferences|GUI"),
3068              new BoolOption (
3069                      "widget-prelight",
3070                      _("Graphically indicate mouse pointer hovering over various widgets"),
3071                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_widget_prelight),
3072                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_widget_prelight)
3073                      ));
3074
3075         add_option (S_("Preferences|GUI"),
3076              new BoolOption (
3077                      "use-tooltips",
3078                      _("Show tooltips if mouse hovers over a control"),
3079                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_tooltips),
3080                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_tooltips)
3081                      ));
3082
3083         add_option (S_("Preferences|GUI"),
3084              new BoolOption (
3085                      "show-name-highlight",
3086                      _("Use name highlight bars in region displays (requires a restart)"),
3087                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_name_highlight),
3088                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_name_highlight)
3089                      ));
3090
3091         add_option (S_("Preferences|GUI"),
3092                     new BoolOption (
3093                             "super-rapid-clock-update",
3094                             _("Update transport clock display at FPS instead of every 100ms"),
3095                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_super_rapid_clock_update),
3096                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_super_rapid_clock_update)
3097                             ));
3098
3099
3100 #ifndef __APPLE__
3101         /* font scaling does nothing with GDK/Quartz */
3102         add_option (S_("Preferences|GUI"), new FontScalingOptions ());
3103 #endif
3104
3105         /* Image cache size */
3106
3107         Gtk::Adjustment *ics = manage (new Gtk::Adjustment(0, 1, 1024, 10)); /* 1 MB to 1GB in steps of 10MB */
3108         HSliderOption *sics = new HSliderOption("waveform-cache-size",
3109                                                 _("Waveform image cache size (megabytes)"),
3110                                                 ics,
3111                                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_cache_size),
3112                                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_cache_size)
3113                         );
3114         sics->scale().set_digits (0);
3115         Gtkmm2ext::UI::instance()->set_tip
3116                 (sics->tip_widget(),
3117                  _("Increasing the cache size uses more memory to store waveform images, which can improve graphical performance."));
3118         add_option (S_("Preferences|GUI"), sics);
3119
3120 if (!ARDOUR::Profile->get_mixbus()) {
3121         /* Lock GUI timeout */
3122
3123         Gtk::Adjustment *lts = manage (new Gtk::Adjustment(0, 0, 1000, 1, 10));
3124         HSliderOption *slts = new HSliderOption("lock-gui-after-seconds",
3125                                                 _("Lock timeout (seconds)"),
3126                                                 lts,
3127                                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_lock_gui_after_seconds),
3128                                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_lock_gui_after_seconds)
3129                         );
3130         slts->scale().set_digits (0);
3131         Gtkmm2ext::UI::instance()->set_tip
3132                 (slts->tip_widget(),
3133                  _("Lock GUI after this many idle seconds (zero to never lock)"));
3134         add_option (S_("Preferences|GUI"), slts);
3135 } // !mixbus
3136
3137         /* The names of these controls must be the same as those given in MixerStrip
3138            for the actual widgets being controlled.
3139         */
3140         _mixer_strip_visibility.add (0, X_("Input"), _("Input"));
3141         _mixer_strip_visibility.add (0, X_("PhaseInvert"), _("Phase Invert"));
3142         _mixer_strip_visibility.add (0, X_("RecMon"), _("Record & Monitor"));
3143         _mixer_strip_visibility.add (0, X_("SoloIsoLock"), _("Solo Iso / Lock"));
3144         _mixer_strip_visibility.add (0, X_("Output"), _("Output"));
3145         _mixer_strip_visibility.add (0, X_("Comments"), _("Comments"));
3146         _mixer_strip_visibility.add (0, X_("VCA"), _("VCA Assigns"));
3147
3148         add_option (
3149                 S_("Preferences|GUI"),
3150                 new VisibilityOption (
3151                         _("Mixer Strip"),
3152                         &_mixer_strip_visibility,
3153                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_mixer_strip_visibility),
3154                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_mixer_strip_visibility)
3155                         )
3156                 );
3157
3158         add_option (S_("Preferences|GUI"),
3159              new BoolOption (
3160                      "default-narrow_ms",
3161                      _("Use narrow strips in the mixer by default"),
3162                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_default_narrow_ms),
3163                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_default_narrow_ms)
3164                      ));
3165
3166         add_option (S_("Preferences|GUI"),
3167                         new ColumVisibilityOption (
3168                                 "action-table-columns", _("Action Script Button Visibility"), 3,
3169                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_action_table_columns),
3170                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_action_table_columns)
3171                                 )
3172                         );
3173
3174         add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Metering")));
3175
3176         ComboOption<float>* mht = new ComboOption<float> (
3177                 "meter-hold",
3178                 _("Peak hold time"),
3179                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_hold),
3180                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_hold)
3181                 );
3182
3183         mht->add (MeterHoldOff, _("off"));
3184         mht->add (MeterHoldShort, _("short"));
3185         mht->add (MeterHoldMedium, _("medium"));
3186         mht->add (MeterHoldLong, _("long"));
3187
3188         add_option (S_("Preferences|Metering"), mht);
3189
3190         ComboOption<float>* mfo = new ComboOption<float> (
3191                 "meter-falloff",
3192                 _("DPM fall-off"),
3193                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_falloff),
3194                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_falloff)
3195                 );
3196
3197         mfo->add (METER_FALLOFF_OFF,      _("off"));
3198         mfo->add (METER_FALLOFF_SLOWEST,  _("slowest [6.6dB/sec]"));
3199         mfo->add (METER_FALLOFF_SLOW,     _("slow [8.6dB/sec] (BBC PPM, EBU PPM)"));
3200         mfo->add (METER_FALLOFF_SLOWISH,  _("moderate [12.0dB/sec] (DIN)"));
3201         mfo->add (METER_FALLOFF_MODERATE, _("medium [13.3dB/sec] (EBU Digi PPM, IRT Digi PPM)"));
3202         mfo->add (METER_FALLOFF_MEDIUM,   _("fast [20dB/sec]"));
3203         mfo->add (METER_FALLOFF_FAST,     _("very fast [32dB/sec]"));
3204
3205         add_option (S_("Preferences|Metering"), mfo);
3206
3207         ComboOption<MeterLineUp>* mlu = new ComboOption<MeterLineUp> (
3208                 "meter-line-up-level",
3209                 _("Meter line-up level; 0dBu"),
3210                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_line_up_level),
3211                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_line_up_level)
3212                 );
3213
3214         mlu->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
3215         mlu->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
3216         mlu->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
3217         mlu->add (MeteringLineUp15, _("-15dBFS (DIN)"));
3218
3219         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."));
3220
3221         add_option (S_("Preferences|Metering"), mlu);
3222
3223         ComboOption<MeterLineUp>* mld = new ComboOption<MeterLineUp> (
3224                 "meter-line-up-din",
3225                 _("IEC1/DIN Meter line-up level; 0dBu"),
3226                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_line_up_din),
3227                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_line_up_din)
3228                 );
3229
3230         mld->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
3231         mld->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
3232         mld->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
3233         mld->add (MeteringLineUp15, _("-15dBFS (DIN)"));
3234
3235         Gtkmm2ext::UI::instance()->set_tip (mld->tip_widget(), _("Reference level for IEC1/DIN meter."));
3236
3237         add_option (S_("Preferences|Metering"), mld);
3238
3239         ComboOption<VUMeterStandard>* mvu = new ComboOption<VUMeterStandard> (
3240                 "meter-vu-standard",
3241                 _("VU Meter standard"),
3242                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_vu_standard),
3243                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_vu_standard)
3244                 );
3245
3246         mvu->add (MeteringVUfrench,   _("0VU = -2dBu (France)"));
3247         mvu->add (MeteringVUamerican, _("0VU = 0dBu (North America, Australia)"));
3248         mvu->add (MeteringVUstandard, _("0VU = +4dBu (standard)"));
3249         mvu->add (MeteringVUeight,    _("0VU = +8dBu"));
3250
3251         add_option (S_("Preferences|Metering"), mvu);
3252
3253         Gtk::Adjustment *mpk = manage (new Gtk::Adjustment(0, -10, 0, .1, .1));
3254         HSliderOption *mpks = new HSliderOption("meter-peak",
3255                         _("Peak threshold [dBFS]"),
3256                         mpk,
3257                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_peak),
3258                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_peak)
3259                         );
3260
3261
3262         ComboOption<MeterType>* mtm = new ComboOption<MeterType> (
3263                 "meter-type-master",
3264                 _("Default Meter Type for Master Bus"),
3265                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_master),
3266                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_master)
3267                 );
3268         mtm->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
3269         mtm->add (MeterK20,     ArdourMeter::meter_type_string(MeterK20));
3270         mtm->add (MeterK14,     ArdourMeter::meter_type_string(MeterK14));
3271         mtm->add (MeterK12,     ArdourMeter::meter_type_string(MeterK12));
3272         mtm->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
3273         mtm->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
3274         mtm->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
3275         mtm->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
3276
3277         add_option (S_("Preferences|Metering"), mtm);
3278
3279
3280         ComboOption<MeterType>* mtb = new ComboOption<MeterType> (
3281                 "meter-type-bus",
3282                 _("Default Meter Type for Busses"),
3283                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_bus),
3284                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_bus)
3285                 );
3286         mtb->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
3287         mtb->add (MeterK20,     ArdourMeter::meter_type_string(MeterK20));
3288         mtb->add (MeterK14,     ArdourMeter::meter_type_string(MeterK14));
3289         mtb->add (MeterK12,     ArdourMeter::meter_type_string(MeterK12));
3290         mtb->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
3291         mtb->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
3292         mtb->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
3293         mtb->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
3294
3295         add_option (S_("Preferences|Metering"), mtb);
3296
3297         ComboOption<MeterType>* mtt = new ComboOption<MeterType> (
3298                 "meter-type-track",
3299                 _("Default Meter Type for Tracks"),
3300                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_track),
3301                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_track)
3302                 );
3303         mtt->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
3304         mtt->add (MeterPeak0dB, ArdourMeter::meter_type_string(MeterPeak0dB));
3305
3306         add_option (S_("Preferences|Metering"), mtt);
3307
3308
3309         Gtkmm2ext::UI::instance()->set_tip
3310                 (mpks->tip_widget(),
3311                  _("Specify the audio signal level in dBFS at and above which the meter-peak indicator will flash red."));
3312
3313         add_option (S_("Preferences|Metering"), mpks);
3314
3315         add_option (S_("Preferences|Metering"),
3316              new BoolOption (
3317                      "meter-style-led",
3318                      _("LED meter style"),
3319                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_style_led),
3320                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_style_led)
3321                      ));
3322
3323         add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Editor Meters")));
3324
3325         add_option (S_("Preferences|Metering"),
3326              new BoolOption (
3327                      "show-track-meters",
3328                      _("Show meters on tracks in the editor"),
3329                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_track_meters),
3330                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_track_meters)
3331                      ));
3332
3333         add_option (S_("Preferences|Metering"),
3334              new BoolOption (
3335                      "editor-stereo-only-meters",
3336                      _("Show at most stereo meters in the track-header"),
3337                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_editor_stereo_only_meters),
3338                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_editor_stereo_only_meters)
3339                      ));
3340
3341         add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Post Export Analysis")));
3342
3343         add_option (S_("Preferences|Metering"),
3344              new BoolOption (
3345                      "save-export-analysis-image",
3346                      _("Save loudness analysis as image file"),
3347                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_save_export_analysis_image),
3348                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_save_export_analysis_image)
3349                      ));
3350
3351         /* and now the theme manager */
3352
3353         ThemeManager* tm = manage (new ThemeManager);
3354         add_page (_("Theme"), *tm);
3355
3356         add_option (_("Theme/Colors"), new ColorThemeManager);
3357
3358         //trigger some parameter-changed messages which affect widget-visibility or -sensitivity
3359         parameter_changed ("send-ltc");
3360         parameter_changed ("sync-source");
3361         parameter_changed ("use-monitor-bus");
3362         parameter_changed ("open-gui-after-adding-plugin");
3363
3364         XMLNode* node = ARDOUR_UI::instance()->preferences_settings();
3365         if (node) {
3366                 /* gcc4 complains about ambiguity with Gtk::Widget::set_state
3367                    (Gtk::StateType) here !!!
3368                 */
3369                 Tabbable::set_state (*node, Stateful::loading_state_version);
3370         }
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 }