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