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