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