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