"Lock" mode is now "Constrained", make snap absolute modifier configurable.
[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 #include <boost/algorithm/string.hpp>    
25
26 #include <gtkmm/liststore.h>
27 #include <gtkmm/stock.h>
28 #include <gtkmm/scale.h>
29
30 #include <gtkmm2ext/utils.h>
31 #include <gtkmm2ext/slider_controller.h>
32 #include <gtkmm2ext/gtk_ui.h>
33 #include <gtkmm2ext/paths_dialog.h>
34
35 #include "pbd/fpu.h"
36 #include "pbd/cpus.h"
37
38 #include "ardour/audioengine.h"
39 #include "ardour/dB.h"
40 #include "ardour/rc_configuration.h"
41 #include "ardour/control_protocol_manager.h"
42 #include "ardour/plugin_manager.h"
43 #include "control_protocol/control_protocol.h"
44
45 #include "canvas/wave_view.h"
46
47 #include "ardour_ui.h"
48 #include "ardour_window.h"
49 #include "ardour_dialog.h"
50 #include "gui_thread.h"
51 #include "midi_tracer.h"
52 #include "rc_option_editor.h"
53 #include "utils.h"
54 #include "midi_port_dialog.h"
55 #include "sfdb_ui.h"
56 #include "keyboard.h"
57 #include "theme_manager.h"
58 #include "ui_config.h"
59 #include "i18n.h"
60
61 using namespace std;
62 using namespace Gtk;
63 using namespace Gtkmm2ext;
64 using namespace PBD;
65 using namespace ARDOUR;
66 using namespace ARDOUR_UI_UTILS;
67
68 class ClickOptions : public OptionEditorBox
69 {
70 public:
71         ClickOptions (RCConfiguration* c, Gtk::Window* p)
72                 : _rc_config (c)
73         {
74                 Table* t = manage (new Table (2, 3));
75                 t->set_spacings (4);
76
77                 Label* l = manage (left_aligned_label (_("Click audio file:")));
78                 t->attach (*l, 0, 1, 0, 1, FILL);
79                 t->attach (_click_path_entry, 1, 2, 0, 1, FILL);
80                 Button* b = manage (new Button (_("Browse...")));
81                 b->signal_clicked().connect (sigc::mem_fun (*this, &ClickOptions::click_browse_clicked));
82                 t->attach (*b, 2, 3, 0, 1, FILL);
83
84                 l = manage (left_aligned_label (_("Click emphasis audio file:")));
85                 t->attach (*l, 0, 1, 1, 2, FILL);
86                 t->attach (_click_emphasis_path_entry, 1, 2, 1, 2, FILL);
87                 b = manage (new Button (_("Browse...")));
88                 b->signal_clicked().connect (sigc::mem_fun (*this, &ClickOptions::click_emphasis_browse_clicked));
89                 t->attach (*b, 2, 3, 1, 2, FILL);
90                 
91                 _box->pack_start (*t, false, false);
92
93                 _click_path_entry.signal_activate().connect (sigc::mem_fun (*this, &ClickOptions::click_changed));      
94                 _click_emphasis_path_entry.signal_activate().connect (sigc::mem_fun (*this, &ClickOptions::click_emphasis_changed));
95         }
96
97         void parameter_changed (string const & p)
98         {
99                 if (p == "click-sound") {
100                         _click_path_entry.set_text (_rc_config->get_click_sound());
101                 } else if (p == "click-emphasis-sound") {
102                         _click_emphasis_path_entry.set_text (_rc_config->get_click_emphasis_sound());
103                 }
104         }
105
106         void set_state_from_config ()
107         {
108                 parameter_changed ("click-sound");
109                 parameter_changed ("click-emphasis-sound");
110         }
111
112 private:
113
114         void click_browse_clicked ()
115         {
116                 SoundFileChooser sfdb (_("Choose Click"));
117
118                 sfdb.show_all ();
119                 sfdb.present ();
120
121                 if (sfdb.run () == RESPONSE_OK) {
122                         click_chosen (sfdb.get_filename());
123                 }
124         }
125
126         void click_chosen (string const & path)
127         {
128                 _click_path_entry.set_text (path);
129                 _rc_config->set_click_sound (path);
130         }
131
132         void click_changed ()
133         {
134                 click_chosen (_click_path_entry.get_text ());
135         }
136         
137         void click_emphasis_browse_clicked ()
138         {
139                 SoundFileChooser sfdb (_("Choose Click Emphasis"));
140
141                 sfdb.show_all ();
142                 sfdb.present ();
143
144                 if (sfdb.run () == RESPONSE_OK) {
145                         click_emphasis_chosen (sfdb.get_filename());
146                 }
147         }
148
149         void click_emphasis_chosen (string const & path)
150         {
151                 _click_emphasis_path_entry.set_text (path);
152                 _rc_config->set_click_emphasis_sound (path);
153         }
154
155         void click_emphasis_changed ()
156         {
157                 click_emphasis_chosen (_click_emphasis_path_entry.get_text ());
158         }
159
160         RCConfiguration* _rc_config;
161         Entry _click_path_entry;
162         Entry _click_emphasis_path_entry;
163 };
164
165 class UndoOptions : public OptionEditorBox
166 {
167 public:
168         UndoOptions (RCConfiguration* c) :
169                 _rc_config (c),
170                 _limit_undo_button (_("Limit undo history to")),
171                 _save_undo_button (_("Save undo history of"))
172         {
173                 Table* t = new Table (2, 3);
174                 t->set_spacings (4);
175
176                 t->attach (_limit_undo_button, 0, 1, 0, 1, FILL);
177                 _limit_undo_spin.set_range (0, 512);
178                 _limit_undo_spin.set_increments (1, 10);
179                 t->attach (_limit_undo_spin, 1, 2, 0, 1, FILL | EXPAND);
180                 Label* l = manage (left_aligned_label (_("commands")));
181                 t->attach (*l, 2, 3, 0, 1);
182
183                 t->attach (_save_undo_button, 0, 1, 1, 2, FILL);
184                 _save_undo_spin.set_range (0, 512);
185                 _save_undo_spin.set_increments (1, 10);
186                 t->attach (_save_undo_spin, 1, 2, 1, 2, FILL | EXPAND);
187                 l = manage (left_aligned_label (_("commands")));
188                 t->attach (*l, 2, 3, 1, 2);
189
190                 _box->pack_start (*t);
191
192                 _limit_undo_button.signal_toggled().connect (sigc::mem_fun (*this, &UndoOptions::limit_undo_toggled));
193                 _limit_undo_spin.signal_value_changed().connect (sigc::mem_fun (*this, &UndoOptions::limit_undo_changed));
194                 _save_undo_button.signal_toggled().connect (sigc::mem_fun (*this, &UndoOptions::save_undo_toggled));
195                 _save_undo_spin.signal_value_changed().connect (sigc::mem_fun (*this, &UndoOptions::save_undo_changed));
196         }
197
198         void parameter_changed (string const & p)
199         {
200                 if (p == "history-depth") {
201                         int32_t const d = _rc_config->get_history_depth();
202                         _limit_undo_button.set_active (d != 0);
203                         _limit_undo_spin.set_sensitive (d != 0);
204                         _limit_undo_spin.set_value (d);
205                 } else if (p == "save-history") {
206                         bool const x = _rc_config->get_save_history ();
207                         _save_undo_button.set_active (x);
208                         _save_undo_spin.set_sensitive (x);
209                 } else if (p == "save-history-depth") {
210                         _save_undo_spin.set_value (_rc_config->get_saved_history_depth());
211                 }
212         }
213
214         void set_state_from_config ()
215         {
216                 parameter_changed ("save-history");
217                 parameter_changed ("history-depth");
218                 parameter_changed ("save-history-depth");
219         }
220
221         void limit_undo_toggled ()
222         {
223                 bool const x = _limit_undo_button.get_active ();
224                 _limit_undo_spin.set_sensitive (x);
225                 int32_t const n = x ? 16 : 0;
226                 _limit_undo_spin.set_value (n);
227                 _rc_config->set_history_depth (n);
228         }
229
230         void limit_undo_changed ()
231         {
232                 _rc_config->set_history_depth (_limit_undo_spin.get_value_as_int ());
233         }
234
235         void save_undo_toggled ()
236         {
237                 bool const x = _save_undo_button.get_active ();
238                 _rc_config->set_save_history (x);
239         }
240
241         void save_undo_changed ()
242         {
243                 _rc_config->set_saved_history_depth (_save_undo_spin.get_value_as_int ());
244         }
245
246 private:
247         RCConfiguration* _rc_config;
248         CheckButton _limit_undo_button;
249         SpinButton _limit_undo_spin;
250         CheckButton _save_undo_button;
251         SpinButton _save_undo_spin;
252 };
253
254
255
256 static const struct {
257     const char *name;
258     guint modifier;
259 } modifiers[] = {
260
261         { "Unmodified", 0 },
262
263 #ifdef GTKOSX
264
265         /* Command = Meta
266            Option/Alt = Mod1
267         */
268         { "Key|Shift", GDK_SHIFT_MASK },
269         { "Command", GDK_META_MASK },
270         { "Control", GDK_CONTROL_MASK },
271         { "Option", GDK_MOD1_MASK },
272         { "Command-Shift", GDK_META_MASK|GDK_SHIFT_MASK },
273         { "Command-Option", GDK_MOD1_MASK|GDK_META_MASK },
274         { "Shift-Option", GDK_SHIFT_MASK|GDK_MOD1_MASK },
275         { "Shift-Command-Option", GDK_MOD5_MASK|GDK_SHIFT_MASK|GDK_META_MASK },
276
277 #else
278         { "Key|Shift", GDK_SHIFT_MASK },
279         { "Control", GDK_CONTROL_MASK },
280         { "Alt (Mod1)", GDK_MOD1_MASK },
281         { "Control-Shift", GDK_CONTROL_MASK|GDK_SHIFT_MASK },
282         { "Control-Alt", GDK_CONTROL_MASK|GDK_MOD1_MASK },
283         { "Shift-Alt", GDK_SHIFT_MASK|GDK_MOD1_MASK },
284         { "Control-Shift-Alt", GDK_CONTROL_MASK|GDK_SHIFT_MASK|GDK_MOD1_MASK },
285         { "Mod2", GDK_MOD2_MASK },
286         { "Mod3", GDK_MOD3_MASK },
287         { "Mod4", GDK_MOD4_MASK },
288         { "Mod5", GDK_MOD5_MASK },
289 #endif
290         { 0, 0 }
291 };
292
293
294 class KeyboardOptions : public OptionEditorBox
295 {
296 public:
297         KeyboardOptions () :
298                   _delete_button_adjustment (3, 1, 12),
299                   _delete_button_spin (_delete_button_adjustment),
300                   _edit_button_adjustment (3, 1, 5),
301                   _edit_button_spin (_edit_button_adjustment),
302                   _insert_note_button_adjustment (3, 1, 5),
303                   _insert_note_button_spin (_insert_note_button_adjustment)
304         {
305                 /* internationalize and prepare for use with combos */
306
307                 vector<string> dumb;
308                 for (int i = 0; modifiers[i].name; ++i) {
309                         dumb.push_back (S_(modifiers[i].name));
310                 }
311
312                 set_popdown_strings (_edit_modifier_combo, dumb);
313                 _edit_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::edit_modifier_chosen));
314
315                 for (int x = 0; modifiers[x].name; ++x) {
316                         if (modifiers[x].modifier == Keyboard::edit_modifier ()) {
317                                 _edit_modifier_combo.set_active_text (S_(modifiers[x].name));
318                                 break;
319                         }
320                 }
321
322                 Table* t = manage (new Table (4, 5));
323                 t->set_spacings (4);
324
325                 Label* l = manage (left_aligned_label (_("Edit using:")));
326                 l->set_name ("OptionsLabel");
327
328                 t->attach (*l, 0, 1, 0, 1, FILL | EXPAND, FILL);
329                 t->attach (_edit_modifier_combo, 1, 2, 0, 1, FILL | EXPAND, FILL);
330
331                 l = manage (new Label (_("+ button")));
332                 l->set_name ("OptionsLabel");
333
334                 t->attach (*l, 3, 4, 0, 1, FILL | EXPAND, FILL);
335                 t->attach (_edit_button_spin, 4, 5, 0, 1, FILL | EXPAND, FILL);
336
337                 _edit_button_spin.set_name ("OptionsEntry");
338                 _edit_button_adjustment.set_value (Keyboard::edit_button());
339                 _edit_button_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::edit_button_changed));
340
341                 set_popdown_strings (_delete_modifier_combo, dumb);
342                 _delete_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::delete_modifier_chosen));
343
344                 for (int x = 0; modifiers[x].name; ++x) {
345                         if (modifiers[x].modifier == Keyboard::delete_modifier ()) {
346                                 _delete_modifier_combo.set_active_text (S_(modifiers[x].name));
347                                 break;
348                         }
349                 }
350
351                 l = manage (left_aligned_label (_("Delete using:")));
352                 l->set_name ("OptionsLabel");
353
354                 t->attach (*l, 0, 1, 1, 2, FILL | EXPAND, FILL);
355                 t->attach (_delete_modifier_combo, 1, 2, 1, 2, FILL | EXPAND, FILL);
356
357                 l = manage (new Label (_("+ button")));
358                 l->set_name ("OptionsLabel");
359
360                 t->attach (*l, 3, 4, 1, 2, FILL | EXPAND, FILL);
361                 t->attach (_delete_button_spin, 4, 5, 1, 2, FILL | EXPAND, FILL);
362
363                 _delete_button_spin.set_name ("OptionsEntry");
364                 _delete_button_adjustment.set_value (Keyboard::delete_button());
365                 _delete_button_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::delete_button_changed));
366
367
368                 set_popdown_strings (_insert_note_modifier_combo, dumb);
369                 _insert_note_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::insert_note_modifier_chosen));
370
371                 for (int x = 0; modifiers[x].name; ++x) {
372                         if (modifiers[x].modifier == Keyboard::insert_note_modifier ()) {
373                                 _insert_note_modifier_combo.set_active_text (S_(modifiers[x].name));
374                                 break;
375                         }
376                 }
377
378                 l = manage (left_aligned_label (_("Insert note using:")));
379                 l->set_name ("OptionsLabel");
380
381                 t->attach (*l, 0, 1, 2, 3, FILL | EXPAND, FILL);
382                 t->attach (_insert_note_modifier_combo, 1, 2, 2, 3, FILL | EXPAND, FILL);
383
384                 l = manage (new Label (_("+ button")));
385                 l->set_name ("OptionsLabel");
386
387                 t->attach (*l, 3, 4, 2, 3, FILL | EXPAND, FILL);
388                 t->attach (_insert_note_button_spin, 4, 5, 2, 3, FILL | EXPAND, FILL);
389
390                 _insert_note_button_spin.set_name ("OptionsEntry");
391                 _insert_note_button_adjustment.set_value (Keyboard::insert_note_button());
392                 _insert_note_button_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::insert_note_button_changed));
393
394                 /* ignore snap */
395                 set_popdown_strings (_snap_modifier_combo, dumb);
396                 _snap_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::snap_modifier_chosen));
397
398                 for (int x = 0; modifiers[x].name; ++x) {
399                         if (modifiers[x].modifier == (guint) Keyboard::snap_modifier ()) {
400                                 _snap_modifier_combo.set_active_text (S_(modifiers[x].name));
401                                 break;
402                         }
403                 }
404
405                 l = manage (left_aligned_label (_("Ignore snap using:")));
406                 l->set_name ("OptionsLabel");
407
408                 t->attach (*l, 0, 1, 3, 4, FILL | EXPAND, FILL);
409                 t->attach (_snap_modifier_combo, 1, 2, 3, 4, FILL | EXPAND, FILL);
410
411                 /* snap delta */
412                 set_popdown_strings (_snap_delta_combo, dumb);
413                 _snap_delta_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::snap_delta_modifier_chosen));
414
415                 for (int x = 0; modifiers[x].name; ++x) {
416                         if (modifiers[x].modifier == (guint) Keyboard::snap_delta_modifier ()) {
417                                 _snap_delta_combo.set_active_text (S_(modifiers[x].name));
418                                 break;
419                         }
420                 }
421
422                 l = manage (left_aligned_label (_("Snap to absolute using:")));
423                 l->set_name ("OptionsLabel");
424
425                 t->attach (*l, 0, 1, 4, 5, FILL | EXPAND, FILL);
426                 t->attach (_snap_delta_combo, 1, 2, 4, 5, FILL | EXPAND, FILL);
427
428                 vector<string> strs;
429
430                 for (map<string,string>::iterator bf = Keyboard::binding_files.begin(); bf != Keyboard::binding_files.end(); ++bf) {
431                         strs.push_back (bf->first);
432                 }
433
434                 set_popdown_strings (_keyboard_layout_selector, strs);
435                 _keyboard_layout_selector.set_active_text (Keyboard::current_binding_name());
436                 _keyboard_layout_selector.signal_changed().connect (sigc::mem_fun (*this, &KeyboardOptions::bindings_changed));
437
438                 l = manage (left_aligned_label (_("Keyboard layout:")));
439                 l->set_name ("OptionsLabel");
440
441                 t->attach (*l, 0, 1, 5, 6, FILL | EXPAND, FILL);
442                 t->attach (_keyboard_layout_selector, 1, 2, 5, 6, FILL | EXPAND, FILL);
443
444                 _box->pack_start (*t, false, false);
445         }
446
447         void parameter_changed (string const &)
448         {
449                 /* XXX: these aren't really config options... */
450         }
451
452         void set_state_from_config ()
453         {
454                 /* XXX: these aren't really config options... */
455         }
456
457 private:
458
459         void bindings_changed ()
460         {
461                 string const txt = _keyboard_layout_selector.get_active_text();
462
463                 /* XXX: config...?  for all this keyboard stuff */
464
465                 for (map<string,string>::iterator i = Keyboard::binding_files.begin(); i != Keyboard::binding_files.end(); ++i) {
466                         if (txt == i->first) {
467                                 if (Keyboard::load_keybindings (i->second)) {
468                                         Keyboard::save_keybindings ();
469                                 }
470                         }
471                 }
472         }
473
474         void edit_modifier_chosen ()
475         {
476                 string const txt = _edit_modifier_combo.get_active_text();
477
478                 for (int i = 0; modifiers[i].name; ++i) {
479                         if (txt == _(modifiers[i].name)) {
480                                 Keyboard::set_edit_modifier (modifiers[i].modifier);
481                                 break;
482                         }
483                 }
484         }
485
486         void delete_modifier_chosen ()
487         {
488                 string const txt = _delete_modifier_combo.get_active_text();
489
490                 for (int i = 0; modifiers[i].name; ++i) {
491                         if (txt == _(modifiers[i].name)) {
492                                 Keyboard::set_delete_modifier (modifiers[i].modifier);
493                                 break;
494                         }
495                 }
496         }
497
498         void insert_note_modifier_chosen ()
499         {
500                 string const txt = _insert_note_modifier_combo.get_active_text();
501
502                 for (int i = 0; modifiers[i].name; ++i) {
503                         if (txt == _(modifiers[i].name)) {
504                                 Keyboard::set_insert_note_modifier (modifiers[i].modifier);
505                                 break;
506                         }
507                 }
508         }
509
510         void snap_modifier_chosen ()
511         {
512                 string const txt = _snap_modifier_combo.get_active_text();
513
514                 for (int i = 0; modifiers[i].name; ++i) {
515                         if (txt == _(modifiers[i].name)) {
516                                 Keyboard::set_snap_modifier (modifiers[i].modifier);
517                                 break;
518                         }
519                 }
520         }
521
522         void snap_delta_modifier_chosen ()
523         {
524                 string const txt = _snap_delta_combo.get_active_text();
525
526                 for (int i = 0; modifiers[i].name; ++i) {
527                         if (txt == _(modifiers[i].name)) {
528                                 Keyboard::set_snap_delta_modifier (modifiers[i].modifier);
529                                 break;
530                         }
531                 }
532         }
533
534         void delete_button_changed ()
535         {
536                 Keyboard::set_delete_button (_delete_button_spin.get_value_as_int());
537         }
538
539         void edit_button_changed ()
540         {
541                 Keyboard::set_edit_button (_edit_button_spin.get_value_as_int());
542         }
543
544         void insert_note_button_changed ()
545         {
546                 Keyboard::set_insert_note_button (_insert_note_button_spin.get_value_as_int());
547         }
548
549         ComboBoxText _keyboard_layout_selector;
550         ComboBoxText _edit_modifier_combo;
551         ComboBoxText _delete_modifier_combo;
552         ComboBoxText _insert_note_modifier_combo;
553         ComboBoxText _snap_modifier_combo;
554         ComboBoxText _snap_delta_combo;
555         Adjustment _delete_button_adjustment;
556         SpinButton _delete_button_spin;
557         Adjustment _edit_button_adjustment;
558         SpinButton _edit_button_spin;
559         Adjustment _insert_note_button_adjustment;
560         SpinButton _insert_note_button_spin;
561
562 };
563
564 class FontScalingOptions : public OptionEditorBox
565 {
566 public:
567         FontScalingOptions (UIConfiguration* uic) :
568                 _ui_config (uic),
569                 _dpi_adjustment (100, 50, 250, 1, 5),
570                 _dpi_slider (_dpi_adjustment)
571         {
572                 _dpi_adjustment.set_value (_ui_config->get_font_scale() / 1024.);
573
574                 Label* l = manage (new Label (_("GUI and Font scaling:")));
575                 l->set_name ("OptionsLabel");
576
577                  const Glib::ustring dflt = _("Default");
578                  const Glib::ustring empty = X_(""); // despite gtk-doc saying so, NULL does not work as reference
579
580                 _dpi_slider.set_name("FontScaleSlider");
581                 _dpi_slider.set_update_policy (UPDATE_DISCONTINUOUS);
582                 _dpi_slider.set_draw_value(false);
583                 _dpi_slider.add_mark(50,  Gtk::POS_TOP, empty);
584                 _dpi_slider.add_mark(60,  Gtk::POS_TOP, empty);
585                 _dpi_slider.add_mark(70,  Gtk::POS_TOP, empty);
586                 _dpi_slider.add_mark(80,  Gtk::POS_TOP, empty);
587                 _dpi_slider.add_mark(90,  Gtk::POS_TOP, empty);
588                 _dpi_slider.add_mark(100, Gtk::POS_TOP, dflt);
589                 _dpi_slider.add_mark(125, Gtk::POS_TOP, empty);
590                 _dpi_slider.add_mark(150, Gtk::POS_TOP, empty);
591                 _dpi_slider.add_mark(175, Gtk::POS_TOP, empty);
592                 _dpi_slider.add_mark(200, Gtk::POS_TOP, empty);
593                 _dpi_slider.add_mark(225, Gtk::POS_TOP, empty);
594                 _dpi_slider.add_mark(250, Gtk::POS_TOP, empty);
595
596                 HBox* h = manage (new HBox);
597                 h->set_spacing (4);
598                 h->pack_start (*l, false, false);
599                 h->pack_start (_dpi_slider, true, true);
600
601                 _box->pack_start (*h, false, false);
602
603                 set_note (_("Adjusting the scale require an application restart to re-layout."));
604
605                 _dpi_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &FontScalingOptions::dpi_changed));
606         }
607
608         void parameter_changed (string const & p)
609         {
610                 if (p == "font-scale") {
611                         _dpi_adjustment.set_value (_ui_config->get_font_scale() / 1024.);
612                 }
613         }
614
615         void set_state_from_config ()
616         {
617                 parameter_changed ("font-scale");
618         }
619
620 private:
621
622         void dpi_changed ()
623         {
624                 _ui_config->set_font_scale ((long) floor (_dpi_adjustment.get_value() * 1024.));
625                 /* XXX: should be triggered from the parameter changed signal */
626                 reset_dpi ();
627         }
628
629         UIConfiguration* _ui_config;
630         Adjustment _dpi_adjustment;
631         HScale _dpi_slider;
632 };
633
634 class ClipLevelOptions : public OptionEditorBox
635 {
636 public:
637         ClipLevelOptions (UIConfiguration* c) 
638                 : _ui_config (c)
639                 , _clip_level_adjustment (-.5, -50.0, 0.0, 0.1, 1.0) /* units of dB */
640                 , _clip_level_slider (_clip_level_adjustment)
641         {
642                 _clip_level_adjustment.set_value (_ui_config->get_waveform_clip_level ());
643
644                 Label* l = manage (new Label (_("Waveform Clip Level (dBFS):")));
645                 l->set_name ("OptionsLabel");
646
647                 _clip_level_slider.set_update_policy (UPDATE_DISCONTINUOUS);
648                 HBox* h = manage (new HBox);
649                 h->set_spacing (4);
650                 h->pack_start (*l, false, false);
651                 h->pack_start (_clip_level_slider, true, true);
652
653                 _box->pack_start (*h, false, false);
654
655                 _clip_level_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &ClipLevelOptions::clip_level_changed));
656         }
657
658         void parameter_changed (string const & p)
659         {
660                 if (p == "waveform-clip-level") {
661                         _clip_level_adjustment.set_value (_ui_config->get_waveform_clip_level());
662                 }
663         }
664
665         void set_state_from_config ()
666         {
667                 parameter_changed ("waveform-clip-level");
668         }
669
670 private:
671
672         void clip_level_changed ()
673         {
674                 _ui_config->set_waveform_clip_level (_clip_level_adjustment.get_value());
675                 /* XXX: should be triggered from the parameter changed signal */
676                 ArdourCanvas::WaveView::set_clip_level (_clip_level_adjustment.get_value());
677         }
678
679         UIConfiguration* _ui_config;
680         Adjustment _clip_level_adjustment;
681         HScale _clip_level_slider;
682 };
683
684 class BufferingOptions : public OptionEditorBox
685 {
686 public:
687         BufferingOptions (RCConfiguration* c)
688                 : _rc_config (c)
689                 , _playback_adjustment (5, 1, 60, 1, 4)
690                 , _capture_adjustment (5, 1, 60, 1, 4)
691                 , _playback_slider (_playback_adjustment)
692                 , _capture_slider (_capture_adjustment)
693         {
694                 _playback_adjustment.set_value (_rc_config->get_audio_playback_buffer_seconds());
695
696                 Label* l = manage (new Label (_("Playback (seconds of buffering):")));
697                 l->set_name ("OptionsLabel");
698
699                 _playback_slider.set_update_policy (UPDATE_DISCONTINUOUS);
700                 HBox* h = manage (new HBox);
701                 h->set_spacing (4);
702                 h->pack_start (*l, false, false);
703                 h->pack_start (_playback_slider, true, true);
704
705                 _box->pack_start (*h, false, false);
706
707                 _capture_adjustment.set_value (_rc_config->get_audio_capture_buffer_seconds());
708
709                 l = manage (new Label (_("Recording (seconds of buffering):")));
710                 l->set_name ("OptionsLabel");
711
712                 _capture_slider.set_update_policy (UPDATE_DISCONTINUOUS);
713                 h = manage (new HBox);
714                 h->set_spacing (4);
715                 h->pack_start (*l, false, false);
716                 h->pack_start (_capture_slider, true, true);
717
718                 _box->pack_start (*h, false, false);
719
720                 _capture_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &BufferingOptions::capture_changed));
721                 _playback_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &BufferingOptions::playback_changed));
722         }
723
724         void parameter_changed (string const & p)
725         {
726                 if (p == "playback-buffer-seconds") {
727                         _playback_adjustment.set_value (_rc_config->get_audio_playback_buffer_seconds());
728                 } else if (p == "capture-buffer-seconds") {
729                         _capture_adjustment.set_value (_rc_config->get_audio_capture_buffer_seconds());
730                 }
731         }
732
733         void set_state_from_config ()
734         {
735                 parameter_changed ("playback-buffer-seconds");
736                 parameter_changed ("capture-buffer-seconds");
737         }
738
739 private:
740
741         void playback_changed ()
742         {
743                 _rc_config->set_audio_playback_buffer_seconds ((long) _playback_adjustment.get_value());
744         }
745
746         void capture_changed ()
747         {
748                 _rc_config->set_audio_capture_buffer_seconds ((long) _capture_adjustment.get_value());
749         }
750
751         RCConfiguration* _rc_config;
752         Adjustment _playback_adjustment;
753         Adjustment _capture_adjustment;
754         HScale _playback_slider;
755         HScale _capture_slider;
756 };
757
758 class ControlSurfacesOptions : public OptionEditorBox
759 {
760 public:
761         ControlSurfacesOptions (Gtk::Window& parent)
762                 : _parent (parent)
763                 , _ignore_view_change (0)
764         {
765                 _store = ListStore::create (_model);
766                 _view.set_model (_store);
767                 _view.append_column (_("Control Surface Protocol"), _model.name);
768                 _view.get_column(0)->set_resizable (true);
769                 _view.get_column(0)->set_expand (true);
770                 _view.append_column_editable (_("Enabled"), _model.enabled);
771                 _view.append_column_editable (_("Feedback"), _model.feedback);
772
773                 _box->pack_start (_view, false, false);
774
775                 Label* label = manage (new Label);
776                 label->set_markup (string_compose (X_("<i>%1</i>"), _("Double-click on a name to edit settings for an enabled protocol")));
777
778                 _box->pack_start (*label, false, false);
779                 label->show ();
780
781                 ControlProtocolManager& m = ControlProtocolManager::instance ();
782                 m.ProtocolStatusChange.connect (protocol_status_connection, MISSING_INVALIDATOR,
783                                                 boost::bind (&ControlSurfacesOptions::protocol_status_changed, this, _1), gui_context());
784
785                 _store->signal_row_changed().connect (sigc::mem_fun (*this, &ControlSurfacesOptions::view_changed));
786                 _view.signal_button_press_event().connect_notify (sigc::mem_fun(*this, &ControlSurfacesOptions::edit_clicked));
787         }
788
789         void parameter_changed (std::string const &)
790         {
791
792         }
793
794         void set_state_from_config ()
795         {
796                 _store->clear ();
797
798                 ControlProtocolManager& m = ControlProtocolManager::instance ();
799                 for (list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
800
801                         if (!(*i)->mandatory) {
802                                 TreeModel::Row r = *_store->append ();
803                                 r[_model.name] = (*i)->name;
804                                 r[_model.enabled] = ((*i)->protocol || (*i)->requested);
805                                 r[_model.feedback] = ((*i)->protocol && (*i)->protocol->get_feedback ());
806                                 r[_model.protocol_info] = *i;
807                         }
808                 }
809         }
810
811 private:
812
813         void protocol_status_changed (ControlProtocolInfo* cpi) {
814                 /* find the row */
815                 TreeModel::Children rows = _store->children();
816                 
817                 for (TreeModel::Children::iterator x = rows.begin(); x != rows.end(); ++x) {
818                         string n = ((*x)[_model.name]);
819
820                         if ((*x)[_model.protocol_info] == cpi) {
821                                 _ignore_view_change++;
822                                 (*x)[_model.enabled] = (cpi->protocol || cpi->requested);
823                                 _ignore_view_change--;
824                                 break;
825                         }
826                 }
827         }
828
829         void view_changed (TreeModel::Path const &, TreeModel::iterator const & i)
830         {
831                 TreeModel::Row r = *i;
832
833                 if (_ignore_view_change) {
834                         return;
835                 }
836
837                 ControlProtocolInfo* cpi = r[_model.protocol_info];
838                 if (!cpi) {
839                         return;
840                 }
841
842                 bool const was_enabled = (cpi->protocol != 0);
843                 bool const is_enabled = r[_model.enabled];
844
845
846                 if (was_enabled != is_enabled) {
847
848                         if (!was_enabled) {
849                                 ControlProtocolManager::instance().activate (*cpi);
850                         } else {
851                                 ControlProtocolManager::instance().deactivate (*cpi);
852                         }
853                 }
854
855                 bool const was_feedback = (cpi->protocol && cpi->protocol->get_feedback ());
856                 bool const is_feedback = r[_model.feedback];
857
858                 if (was_feedback != is_feedback && cpi->protocol) {
859                         cpi->protocol->set_feedback (is_feedback);
860                 }
861         }
862
863         void edit_clicked (GdkEventButton* ev)
864         {
865                 if (ev->type != GDK_2BUTTON_PRESS) {
866                         return;
867                 }
868
869                 std::string name;
870                 ControlProtocolInfo* cpi;
871                 TreeModel::Row row;
872
873                 row = *(_view.get_selection()->get_selected());
874                 if (!row[_model.enabled]) {
875                         return;
876                 }
877                 cpi = row[_model.protocol_info];
878                 if (!cpi || !cpi->protocol || !cpi->protocol->has_editor ()) {
879                         return;
880                 }
881                 Box* box = (Box*) cpi->protocol->get_gui ();
882                 if (!box) {
883                         return;
884                 }
885                 if (box->get_parent()) {
886                         static_cast<ArdourWindow*>(box->get_parent())->present();
887                         return;
888                 }
889                 string title = row[_model.name];
890                 /* once created, the window is managed by the surface itself (as ->get_parent())
891                  * Surface's tear_down_gui() is called on session close, when de-activating
892                  * or re-initializing a surface.
893                  * tear_down_gui() hides an deletes the Window if it exists.
894                  */
895                 ArdourWindow* win = new ArdourWindow (_parent, title);
896                 win->set_title ("Control Protocol Options");
897                 win->add (*box);
898                 box->show ();
899                 win->present ();
900         }
901
902         class ControlSurfacesModelColumns : public TreeModelColumnRecord
903         {
904         public:
905
906                 ControlSurfacesModelColumns ()
907                 {
908                         add (name);
909                         add (enabled);
910                         add (feedback);
911                         add (protocol_info);
912                 }
913
914                 TreeModelColumn<string> name;
915                 TreeModelColumn<bool> enabled;
916                 TreeModelColumn<bool> feedback;
917                 TreeModelColumn<ControlProtocolInfo*> protocol_info;
918         };
919
920         Glib::RefPtr<ListStore> _store;
921         ControlSurfacesModelColumns _model;
922         TreeView _view;
923         Gtk::Window& _parent;
924         PBD::ScopedConnection protocol_status_connection;
925         uint32_t _ignore_view_change;
926 };
927
928 class VideoTimelineOptions : public OptionEditorBox
929 {
930 public:
931         VideoTimelineOptions (RCConfiguration* c)
932                 : _rc_config (c)
933                 , _show_video_export_info_button (_("Show Video Export Info before export"))
934                 , _show_video_server_dialog_button (_("Show Video Server Startup Dialog"))
935                 , _video_advanced_setup_button (_("Advanced Setup (remote video server)"))
936         {
937                 Table* t = manage (new Table (2, 6));
938                 t->set_spacings (4);
939
940                 t->attach (_video_advanced_setup_button, 0, 2, 0, 1);
941                 _video_advanced_setup_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::video_advanced_setup_toggled));
942                 Gtkmm2ext::UI::instance()->set_tip (_video_advanced_setup_button,
943                                             _("<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."));
944
945                 Label* l = manage (new Label (_("Video Server URL:")));
946                 l->set_alignment (0, 0.5);
947                 t->attach (*l, 0, 1, 1, 2, FILL);
948                 t->attach (_video_server_url_entry, 1, 2, 1, 2, FILL);
949                 Gtkmm2ext::UI::instance()->set_tip (_video_server_url_entry,
950                                             _("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"));
951
952                 l = manage (new Label (_("Video Folder:")));
953                 l->set_alignment (0, 0.5);
954                 t->attach (*l, 0, 1, 2, 3, FILL);
955                 t->attach (_video_server_docroot_entry, 1, 2, 2, 3);
956                 Gtkmm2ext::UI::instance()->set_tip (_video_server_docroot_entry,
957                                             _("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."));
958
959                 /* small vspace  y=3..4 */
960
961                 t->attach (_show_video_export_info_button, 0, 2, 4, 5);
962                 _show_video_export_info_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::show_video_export_info_toggled));
963                 Gtkmm2ext::UI::instance()->set_tip (_show_video_export_info_button,
964                                             _("<b>When enabled</b> an information window with details is displayed before the video-export dialog."));
965
966                 t->attach (_show_video_server_dialog_button, 0, 2, 5, 6);
967                 _show_video_server_dialog_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::show_video_server_dialog_toggled));
968                 Gtkmm2ext::UI::instance()->set_tip (_show_video_server_dialog_button,
969                                             _("<b>When enabled</b> the video server is never launched automatically without confirmation"));
970
971                 _video_server_url_entry.signal_changed().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_url_changed));
972                 _video_server_url_entry.signal_activate().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_url_changed));
973                 _video_server_docroot_entry.signal_changed().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_docroot_changed));
974                 _video_server_docroot_entry.signal_activate().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_docroot_changed));
975
976                 _box->pack_start (*t,true,true);
977         }
978
979         void server_url_changed ()
980         {
981                 _rc_config->set_video_server_url (_video_server_url_entry.get_text());
982         }
983
984         void server_docroot_changed ()
985         {
986                 _rc_config->set_video_server_docroot (_video_server_docroot_entry.get_text());
987         }
988
989         void show_video_export_info_toggled ()
990         {
991                 bool const x = _show_video_export_info_button.get_active ();
992                 _rc_config->set_show_video_export_info (x);
993         }
994
995         void show_video_server_dialog_toggled ()
996         {
997                 bool const x = _show_video_server_dialog_button.get_active ();
998                 _rc_config->set_show_video_server_dialog (x);
999         }
1000
1001         void video_advanced_setup_toggled ()
1002         {
1003                 bool const x = _video_advanced_setup_button.get_active ();
1004                 _rc_config->set_video_advanced_setup(x);
1005         }
1006
1007         void parameter_changed (string const & p)
1008         {
1009                 if (p == "video-server-url") {
1010                         _video_server_url_entry.set_text (_rc_config->get_video_server_url());
1011                 } else if (p == "video-server-docroot") {
1012                         _video_server_docroot_entry.set_text (_rc_config->get_video_server_docroot());
1013                 } else if (p == "show-video-export-info") {
1014                         bool const x = _rc_config->get_show_video_export_info();
1015                         _show_video_export_info_button.set_active (x);
1016                 } else if (p == "show-video-server-dialog") {
1017                         bool const x = _rc_config->get_show_video_server_dialog();
1018                         _show_video_server_dialog_button.set_active (x);
1019                 } else if (p == "video-advanced-setup") {
1020                         bool const x = _rc_config->get_video_advanced_setup();
1021                         _video_advanced_setup_button.set_active(x);
1022                         _video_server_docroot_entry.set_sensitive(x);
1023                         _video_server_url_entry.set_sensitive(x);
1024                 }
1025         }
1026
1027         void set_state_from_config ()
1028         {
1029                 parameter_changed ("video-server-url");
1030                 parameter_changed ("video-server-docroot");
1031                 parameter_changed ("video-monitor-setup-dialog");
1032                 parameter_changed ("show-video-export-info");
1033                 parameter_changed ("show-video-server-dialog");
1034                 parameter_changed ("video-advanced-setup");
1035         }
1036
1037 private:
1038         RCConfiguration* _rc_config;
1039         Entry _video_server_url_entry;
1040         Entry _video_server_docroot_entry;
1041         CheckButton _show_video_export_info_button;
1042         CheckButton _show_video_server_dialog_button;
1043         CheckButton _video_advanced_setup_button;
1044 };
1045
1046 class PluginOptions : public OptionEditorBox
1047 {
1048 public:
1049         PluginOptions (RCConfiguration* c, UIConfiguration* uic)
1050                 : _rc_config (c)
1051                 , _ui_config (uic)
1052                 , _display_plugin_scan_progress (_("Always Display Plugin Scan Progress"))
1053                 , _discover_vst_on_start (_("Scan for [new] VST Plugins on Application Start"))
1054                 , _discover_au_on_start (_("Scan for AudioUnit Plugins on Application Start"))
1055                 , _timeout_adjustment (0, 0, 3000, 50, 50)
1056                 , _timeout_slider (_timeout_adjustment)
1057         {
1058                 Label *l;
1059                 std::stringstream ss;
1060                 Table* t = manage (new Table (2, 6));
1061                 t->set_spacings (4);
1062                 Button* b;
1063                 int n = 0;
1064
1065                 ss << "<b>" << _("General") << "</b>";
1066                 l = manage (left_aligned_label (ss.str()));
1067                 l->set_use_markup (true);
1068                 t->attach (*manage (new Label ("")), 0, 3, n, n+1, FILL | EXPAND); ++n;
1069                 t->attach (*l, 0, 2, n, n+1, FILL | EXPAND); ++n;
1070
1071                 b = manage (new Button (_("Scan for Plugins")));
1072                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::refresh_clicked));
1073                 t->attach (*b, 0, 2, n, n+1, FILL); ++n;
1074
1075                 t->attach (_display_plugin_scan_progress, 0, 2, n, n+1); ++n;
1076                 _display_plugin_scan_progress.signal_toggled().connect (sigc::mem_fun (*this, &PluginOptions::display_plugin_scan_progress_toggled));
1077                 Gtkmm2ext::UI::instance()->set_tip (_display_plugin_scan_progress,
1078                                             _("<b>When enabled</b> a popup window showing plugin scan progress is displayed for indexing (cache load) and discovery (detect new plugins)"));
1079
1080 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
1081                 _timeout_slider.set_digits (0);
1082                 _timeout_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &PluginOptions::timeout_changed));
1083
1084                 Gtkmm2ext::UI::instance()->set_tip(_timeout_slider,
1085                          _("Specify the default timeout for plugin instantiation in 1/10 seconds. Plugins that require more time to load will be blacklisted. A value of 0 disables the timeout."));
1086
1087                 l = manage (left_aligned_label (_("Scan Time Out [deciseconds]")));;
1088                 HBox* h = manage (new HBox);
1089                 h->set_spacing (4);
1090                 h->pack_start (*l, false, false);
1091                 h->pack_start (_timeout_slider, true, true);
1092                 t->attach (*h, 0, 2, n, n+1); ++n;
1093
1094                 ss.str("");
1095                 ss << "<b>" << _("VST") << "</b>";
1096                 l = manage (left_aligned_label (ss.str()));
1097                 l->set_use_markup (true);
1098                 t->attach (*manage (new Label ("")), 0, 3, n, n+1, FILL | EXPAND); ++n;
1099                 t->attach (*l, 0, 2, n, n+1, FILL | EXPAND); ++n;
1100
1101                 b = manage (new Button (_("Clear VST Cache")));
1102                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::clear_vst_cache_clicked));
1103                 t->attach (*b, 0, 1, n, n+1, FILL);
1104
1105                 b = manage (new Button (_("Clear VST Blacklist")));
1106                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::clear_vst_blacklist_clicked));
1107                 t->attach (*b, 1, 2, n, n+1, FILL);
1108                 ++n;
1109
1110                 t->attach (_discover_vst_on_start, 0, 2, n, n+1); ++n;
1111                 _discover_vst_on_start.signal_toggled().connect (sigc::mem_fun (*this, &PluginOptions::discover_vst_on_start_toggled));
1112                 Gtkmm2ext::UI::instance()->set_tip (_discover_vst_on_start,
1113                                             _("<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"));
1114
1115 #ifdef LXVST_SUPPORT
1116                 t->attach (*manage (left_aligned_label (_("Linux VST Path:"))), 0, 1, n, n+1);
1117                 b = manage (new Button (_("Edit")));
1118                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::edit_lxvst_path_clicked));
1119                 t->attach (*b, 1, 2, n, n+1, FILL); ++n;
1120 #endif
1121
1122 #ifdef WINDOWS_VST_SUPPORT
1123                 t->attach (*manage (left_aligned_label (_("Windows VST Path:"))), 0, 1, n, n+1);
1124                 b = manage (new Button (_("Edit")));
1125                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::edit_vst_path_clicked));
1126                 t->attach (*b, 1, 2, n, n+1, FILL); ++n;
1127 #endif
1128 #endif // any VST
1129
1130 #ifdef AUDIOUNIT_SUPPORT
1131                 ss.str("");
1132                 ss << "<b>" << _("Audio Unit") << "</b>";
1133                 l = manage (left_aligned_label (ss.str()));
1134                 l->set_use_markup (true);
1135                 t->attach (*manage (new Label ("")), 0, 3, n, n+1, FILL | EXPAND); ++n;
1136                 t->attach (*l, 0, 2, n, n+1, FILL | EXPAND); ++n;
1137
1138                 t->attach (_discover_au_on_start, 0, 2, n, n+1); ++n;
1139                 _discover_au_on_start.signal_toggled().connect (sigc::mem_fun (*this, &PluginOptions::discover_au_on_start_toggled));
1140                 Gtkmm2ext::UI::instance()->set_tip (_discover_au_on_start,
1141                                             _("<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."));
1142
1143                 ++n;
1144                 b = manage (new Button (_("Clear AU Cache")));
1145                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::clear_au_cache_clicked));
1146                 t->attach (*b, 0, 1, n, n+1, FILL);
1147
1148                 b = manage (new Button (_("Clear AU Blacklist")));
1149                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::clear_au_blacklist_clicked));
1150                 t->attach (*b, 1, 2, n, n+1, FILL);
1151                 ++n;
1152 #endif
1153
1154                 _box->pack_start (*t,true,true);
1155         }
1156
1157         void parameter_changed (string const & p) {
1158                 if (p == "show-plugin-scan-window") {
1159                         bool const x = _ui_config->get_show_plugin_scan_window();
1160                         _display_plugin_scan_progress.set_active (x);
1161                 }
1162                 else if (p == "discover-vst-on-start") {
1163                         bool const x = _rc_config->get_discover_vst_on_start();
1164                         _discover_vst_on_start.set_active (x);
1165                 }
1166                 else if (p == "vst-scan-timeout") {
1167                         int const x = _rc_config->get_vst_scan_timeout();
1168                         _timeout_adjustment.set_value (x);
1169                 }
1170                 else if (p == "discover-audio-units") {
1171                         bool const x = _rc_config->get_discover_audio_units();
1172                         _discover_au_on_start.set_active (x);
1173                 }
1174         }
1175
1176         void set_state_from_config () {
1177                 parameter_changed ("show-plugin-scan-window");
1178                 parameter_changed ("discover-vst-on-start");
1179                 parameter_changed ("vst-scan-timeout");
1180                 parameter_changed ("discover-audio-units");
1181         }
1182
1183 private:
1184         RCConfiguration* _rc_config;
1185         UIConfiguration* _ui_config;
1186         CheckButton _display_plugin_scan_progress;
1187         CheckButton _discover_vst_on_start;
1188         CheckButton _discover_au_on_start;
1189         Adjustment _timeout_adjustment;
1190         HScale _timeout_slider;
1191
1192         void display_plugin_scan_progress_toggled () {
1193                 bool const x = _display_plugin_scan_progress.get_active();
1194                 _ui_config->set_show_plugin_scan_window(x);
1195         }
1196
1197         void discover_vst_on_start_toggled () {
1198                 bool const x = _discover_vst_on_start.get_active();
1199                 _rc_config->set_discover_vst_on_start(x);
1200         }
1201
1202         void discover_au_on_start_toggled () {
1203                 bool const x = _discover_au_on_start.get_active();
1204                 _rc_config->set_discover_audio_units(x);
1205         }
1206
1207         void timeout_changed () {
1208                 int x = floor(_timeout_adjustment.get_value());
1209                 _rc_config->set_vst_scan_timeout(x);
1210         }
1211
1212         void clear_vst_cache_clicked () {
1213                 PluginManager::instance().clear_vst_cache();
1214         }
1215
1216         void clear_vst_blacklist_clicked () {
1217                 PluginManager::instance().clear_vst_blacklist();
1218         }
1219
1220         void clear_au_cache_clicked () {
1221                 PluginManager::instance().clear_au_cache();
1222         }
1223
1224         void clear_au_blacklist_clicked () {
1225                 PluginManager::instance().clear_au_blacklist();
1226         }
1227
1228
1229         void edit_vst_path_clicked () {
1230                 Gtkmm2ext::PathsDialog *pd = new Gtkmm2ext::PathsDialog (
1231                                 _("Set Windows VST Search Path"),
1232                                 _rc_config->get_plugin_path_vst(),
1233                                 PluginManager::instance().get_default_windows_vst_path()
1234                         );
1235                 ResponseType r = (ResponseType) pd->run ();
1236                 pd->hide();
1237                 if (r == RESPONSE_ACCEPT) {
1238                         _rc_config->set_plugin_path_vst(pd->get_serialized_paths());
1239                 }
1240                 delete pd;
1241         }
1242
1243         // todo consolidate with edit_vst_path_clicked..
1244         void edit_lxvst_path_clicked () {
1245                 Gtkmm2ext::PathsDialog *pd = new Gtkmm2ext::PathsDialog (
1246                                 _("Set Linux VST Search Path"),
1247                                 _rc_config->get_plugin_path_lxvst(),
1248                                 PluginManager::instance().get_default_lxvst_path()
1249                                 );
1250                 ResponseType r = (ResponseType) pd->run ();
1251                 pd->hide();
1252                 if (r == RESPONSE_ACCEPT) {
1253                         _rc_config->set_plugin_path_lxvst(pd->get_serialized_paths());
1254                 }
1255                 delete pd;
1256         }
1257
1258         void refresh_clicked () {
1259                 PluginManager::instance().refresh();
1260         }
1261 };
1262
1263
1264 /** A class which allows control of visibility of some editor components usign
1265  *  a VisibilityGroup.  The caller should pass in a `dummy' VisibilityGroup
1266  *  which has the correct members, but with null widget pointers.  This
1267  *  class allows the user to set visibility of the members, the details
1268  *  of which are stored in a configuration variable which can be watched
1269  *  by parts of the editor that actually contain the widgets whose visibility
1270  *  is being controlled.
1271  */
1272
1273 class VisibilityOption : public Option
1274 {
1275 public:
1276         /** @param name User-visible name for this group.
1277          *  @param g `Dummy' VisibilityGroup (as described above).
1278          *  @param get Method to get the value of the appropriate configuration variable.
1279          *  @param set Method to set the value of the appropriate configuration variable.
1280          */
1281         VisibilityOption (string name, VisibilityGroup* g, sigc::slot<string> get, sigc::slot<bool, string> set)
1282                 : Option (g->get_state_name(), name)
1283                 , _heading (name)
1284                 , _visibility_group (g)
1285                 , _get (get)
1286                 , _set (set)
1287         {
1288                 /* Watch for changes made by the user to our members */
1289                 _visibility_group->VisibilityChanged.connect_same_thread (
1290                         _visibility_group_connection, sigc::bind (&VisibilityOption::changed, this)
1291                         );
1292         }
1293
1294         void set_state_from_config ()
1295         {
1296                 /* Set our state from the current configuration */
1297                 _visibility_group->set_state (_get ());
1298         }
1299
1300         void add_to_page (OptionEditorPage* p)
1301         {
1302                 _heading.add_to_page (p);
1303                 add_widget_to_page (p, _visibility_group->list_view ());
1304         }
1305
1306         Gtk::Widget& tip_widget() { return *_visibility_group->list_view (); }
1307
1308 private:
1309         void changed ()
1310         {
1311                 /* The user has changed something, so reflect this change
1312                    in the RCConfiguration.
1313                 */
1314                 _set (_visibility_group->get_state_value ());
1315         }
1316         
1317         OptionEditorHeading _heading;
1318         VisibilityGroup* _visibility_group;
1319         sigc::slot<std::string> _get;
1320         sigc::slot<bool, std::string> _set;
1321         PBD::ScopedConnection _visibility_group_connection;
1322 };
1323
1324
1325
1326 RCOptionEditor::RCOptionEditor ()
1327         : OptionEditor (Config, string_compose (_("%1 Preferences"), PROGRAM_NAME))
1328         , _rc_config (Config)
1329         , _ui_config (ARDOUR_UI::config())
1330         , _mixer_strip_visibility ("mixer-element-visibility")
1331 {
1332         /* MISC */
1333
1334         uint32_t hwcpus = hardware_concurrency ();
1335         BoolOption* bo;
1336         BoolComboOption* bco;
1337
1338         if (hwcpus > 1) {
1339                 add_option (_("Misc"), new OptionEditorHeading (_("DSP CPU Utilization")));
1340
1341                 ComboOption<int32_t>* procs = new ComboOption<int32_t> (
1342                         "processor-usage",
1343                         _("Signal processing uses"),
1344                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_processor_usage),
1345                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_processor_usage)
1346                         );
1347
1348                 procs->add (-1, _("all but one processor"));
1349                 procs->add (0, _("all available processors"));
1350
1351                 for (uint32_t i = 1; i <= hwcpus; ++i) {
1352                         procs->add (i, string_compose (_("%1 processors"), i));
1353                 }
1354
1355                 procs->set_note (string_compose (_("This setting will only take effect when %1 is restarted."), PROGRAM_NAME));
1356
1357                 add_option (_("Misc"), procs);
1358         }
1359
1360         add_option (_("Misc"), new OptionEditorHeading (S_("Options|Undo")));
1361
1362         add_option (_("Misc"), new UndoOptions (_rc_config));
1363
1364         add_option (_("Misc"),
1365              new BoolOption (
1366                      "verify-remove-last-capture",
1367                      _("Verify removal of last capture"),
1368                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_verify_remove_last_capture),
1369                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_verify_remove_last_capture)
1370                      ));
1371
1372         add_option (_("Misc"),
1373              new BoolOption (
1374                      "periodic-safety-backups",
1375                      _("Make periodic backups of the session file"),
1376                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_periodic_safety_backups),
1377                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_periodic_safety_backups)
1378                      ));
1379
1380         add_option (_("Misc"), new OptionEditorHeading (_("Session Management")));
1381
1382         add_option (_("Misc"),
1383              new BoolOption (
1384                      "only-copy-imported-files",
1385                      _("Always copy imported files"),
1386                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_only_copy_imported_files),
1387                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_only_copy_imported_files)
1388                      ));
1389
1390         add_option (_("Misc"), new DirectoryOption (
1391                             X_("default-session-parent-dir"),
1392                             _("Default folder for new sessions:"),
1393                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_default_session_parent_dir),
1394                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_default_session_parent_dir)
1395                             ));
1396
1397         add_option (_("Misc"),
1398              new SpinOption<uint32_t> (
1399                      "max-recent-sessions",
1400                      _("Maximum number of recent sessions"),
1401                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_max_recent_sessions),
1402                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_max_recent_sessions),
1403                      0, 1000, 1, 20
1404                      ));
1405
1406         add_option (_("Misc"), new OptionEditorHeading (_("Click")));
1407
1408         add_option (_("Misc"), new ClickOptions (_rc_config, this));
1409
1410         add_option (_("Misc"),
1411              new FaderOption (
1412                      "click-gain",
1413                      _("Click gain level"),
1414                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_click_gain),
1415                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_click_gain)
1416                      ));
1417
1418         add_option (_("Misc"), new OptionEditorHeading (_("Automation")));
1419
1420         add_option (_("Misc"),
1421              new SpinOption<double> (
1422                      "automation-thinning-factor",
1423                      _("Thinning factor (larger value => less data)"),
1424                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_thinning_factor),
1425                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_thinning_factor),
1426                      0, 1000, 1, 20
1427                      ));
1428
1429         add_option (_("Misc"),
1430              new SpinOption<double> (
1431                      "automation-interval-msecs",
1432                      _("Automation sampling interval (milliseconds)"),
1433                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_interval_msecs),
1434                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_interval_msecs),
1435                      1, 1000, 1, 20
1436                      ));
1437
1438         /* TRANSPORT */
1439
1440         BoolOption* tsf;
1441
1442         tsf = new BoolOption (
1443                      "latched-record-enable",
1444                      _("Keep record-enable engaged on stop"),
1445                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_latched_record_enable),
1446                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_latched_record_enable)
1447                      );
1448         // Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _(""));
1449         add_option (_("Transport"), tsf);
1450
1451         tsf = new BoolOption (
1452                      "loop-is-mode",
1453                      _("Play loop is a transport mode"),
1454                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_loop_is_mode),
1455                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_loop_is_mode)
1456                      );
1457         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), 
1458                                             (_("<b>When enabled</b> the loop button does not start playback but forces playback to always play the loop\n\n"
1459                                                "<b>When disabled</b> the loop button starts playing the loop, but stop then cancels loop playback")));
1460         add_option (_("Transport"), tsf);
1461         
1462         tsf = new BoolOption (
1463                      "stop-recording-on-xrun",
1464                      _("Stop recording when an xrun occurs"),
1465                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_recording_on_xrun),
1466                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_recording_on_xrun)
1467                      );
1468         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), 
1469                                             string_compose (_("<b>When enabled</b> %1 will stop recording if an over- or underrun is detected by the audio engine"),
1470                                                             PROGRAM_NAME));
1471         add_option (_("Transport"), tsf);
1472
1473         tsf = new BoolOption (
1474                      "create-xrun-marker",
1475                      _("Create markers where xruns occur"),
1476                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_create_xrun_marker),
1477                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_create_xrun_marker)
1478                      );
1479         // Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _(""));
1480         add_option (_("Transport"), tsf);
1481
1482         tsf = new BoolOption (
1483                      "stop-at-session-end",
1484                      _("Stop at the end of the session"),
1485                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_at_session_end),
1486                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_at_session_end)
1487                      );
1488         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), 
1489                                             string_compose (_("<b>When enabled</b> if %1 is <b>not recording</b>, it will stop the transport "
1490                                                               "when it reaches the current session end marker\n\n"
1491                                                               "<b>When disabled</b> %1 will continue to roll past the session end marker at all times"),
1492                                                             PROGRAM_NAME));
1493         add_option (_("Transport"), tsf);
1494
1495         tsf = new BoolOption (
1496                      "seamless-loop",
1497                      _("Do seamless looping (not possible when slaved to MTC, LTC etc)"),
1498                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_seamless_loop),
1499                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_seamless_loop)
1500                      );
1501         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), 
1502                                             string_compose (_("<b>When enabled</b> this will loop by reading ahead and wrapping around at the loop point, "
1503                                                               "preventing any need to do a transport locate at the end of the loop\n\n"
1504                                                               "<b>When disabled</b> looping is done by locating back to the start of the loop when %1 reaches the end "
1505                                                               "which will often cause a small click or delay"), PROGRAM_NAME));
1506         add_option (_("Transport"), tsf);
1507
1508         tsf = new BoolOption (
1509                      "disable-disarm-during-roll",
1510                      _("Disable per-track record disarm while rolling"),
1511                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_disable_disarm_during_roll),
1512                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_disable_disarm_during_roll)
1513                      );
1514         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _("<b>When enabled</b> this will prevent you from accidentally stopping specific tracks recording during a take"));
1515         add_option (_("Transport"), tsf);
1516
1517         tsf = new BoolOption (
1518                      "quieten_at_speed",
1519                      _("12dB gain reduction during fast-forward and fast-rewind"),
1520                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_quieten_at_speed),
1521                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_quieten_at_speed)
1522                      );
1523         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _("This will reduce the unpleasant increase in perceived volume "
1524                                                    "that occurs when fast-forwarding or rewinding through some kinds of audio"));
1525         add_option (_("Transport"), tsf);
1526
1527         add_option (_("Transport"), new OptionEditorHeading (S_("Sync/Slave")));
1528
1529         _sync_source = new ComboOption<SyncSource> (
1530                 "sync-source",
1531                 _("External timecode source"),
1532                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_sync_source),
1533                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_sync_source)
1534                 );
1535
1536         add_option (_("Transport"), _sync_source);
1537
1538         _sync_framerate = new BoolOption (
1539                      "timecode-sync-frame-rate",
1540                      _("Match session video frame rate to external timecode"),
1541                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_sync_frame_rate),
1542                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_sync_frame_rate)
1543                      );
1544         Gtkmm2ext::UI::instance()->set_tip 
1545                 (_sync_framerate->tip_widget(),
1546                  string_compose (_("This option controls the value of the video frame rate <i>while chasing</i> an external timecode source.\n\n"
1547                                    "<b>When enabled</b> the session video frame rate will be changed to match that of the selected external timecode source.\n\n"
1548                                    "<b>When disabled</b> the session video frame rate will not be changed to match that of the selected external timecode source."
1549                                    "Instead the frame rate indication in the main clock will flash red and %1 will convert between the external "
1550                                    "timecode standard and the session standard."), PROGRAM_NAME));
1551
1552         add_option (_("Transport"), _sync_framerate);
1553
1554         _sync_genlock = new BoolOption (
1555                 "timecode-source-is-synced",
1556                 _("Sync-lock timecode to clock (disable drift compensation)"),
1557                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_is_synced),
1558                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_is_synced)
1559                 );
1560         Gtkmm2ext::UI::instance()->set_tip 
1561                 (_sync_genlock->tip_widget(),
1562                  string_compose (_("<b>When enabled</b> %1 will never varispeed when slaved to external timecode. "
1563                                    "Sync Lock indicates that the selected external timecode source shares clock-sync "
1564                                    "(Black &amp; Burst, Wordclock, etc) with the audio interface. "
1565                                    "This option disables drift compensation. The transport speed is fixed at 1.0. "
1566                                    "Vari-speed LTC will be ignored and cause drift."
1567                                    "\n\n"
1568                                    "<b>When disabled</b> %1 will compensate for potential drift, regardless if the "
1569                                    "timecode sources shares clock sync."
1570                                   ), PROGRAM_NAME));
1571
1572
1573         add_option (_("Transport"), _sync_genlock);
1574
1575         _sync_source_2997 = new BoolOption (
1576                 "timecode-source-2997",
1577                 _("Lock to 29.9700 fps instead of 30000/1001"),
1578                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_2997),
1579                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_2997)
1580                 );
1581         Gtkmm2ext::UI::instance()->set_tip
1582                 (_sync_source_2997->tip_widget(),
1583                  _("<b>When enabled</b> the external timecode source is assumed to use 29.97 fps instead of 30000/1001.\n"
1584                          "SMPTE 12M-1999 specifies 29.97df as 30000/1001. The spec further mentions that "
1585                          "drop-frame timecode has an accumulated error of -86ms over a 24-hour period.\n"
1586                          "Drop-frame timecode would compensate exactly for a NTSC color frame rate of 30 * 0.9990 (ie 29.970000). "
1587                          "That is not the actual rate. However, some vendors use that rate - despite it being against the specs - "
1588                          "because the variant of using exactly 29.97 fps has zero timecode drift.\n"
1589                          ));
1590
1591         add_option (_("Transport"), _sync_source_2997);
1592
1593         add_option (_("Transport"), new OptionEditorHeading (S_("LTC Reader")));
1594
1595         _ltc_port = new ComboStringOption (
1596                 "ltc-source-port",
1597                 _("LTC incoming port"),
1598                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_source_port),
1599                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_source_port)
1600                 );
1601
1602         vector<string> physical_inputs;
1603         physical_inputs.push_back (_("None"));
1604         AudioEngine::instance()->get_physical_inputs (DataType::AUDIO, physical_inputs);
1605         _ltc_port->set_popdown_strings (physical_inputs);
1606
1607         populate_sync_options ();
1608
1609         add_option (_("Transport"), _ltc_port);
1610
1611         // TODO; rather disable this button than not compile it..
1612         add_option (_("Transport"), new OptionEditorHeading (S_("LTC Generator")));
1613
1614         add_option (_("Transport"),
1615                     new BoolOption (
1616                             "send-ltc",
1617                             _("Enable LTC generator"),
1618                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_ltc),
1619                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_ltc)
1620                             ));
1621
1622         _ltc_send_continuously = new BoolOption (
1623                             "ltc-send-continuously",
1624                             _("Send LTC while stopped"),
1625                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_send_continuously),
1626                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_send_continuously)
1627                             );
1628         Gtkmm2ext::UI::instance()->set_tip
1629                 (_ltc_send_continuously->tip_widget(),
1630                  string_compose (_("<b>When enabled</b> %1 will continue to send LTC information even when the transport (playhead) is not moving"), PROGRAM_NAME));
1631         add_option (_("Transport"), _ltc_send_continuously);
1632
1633         _ltc_volume_adjustment = new Gtk::Adjustment(-18, -50, 0, .5, 5);
1634         _ltc_volume_adjustment->set_value (20 * log10(_rc_config->get_ltc_output_volume()));
1635         _ltc_volume_adjustment->signal_value_changed().connect (sigc::mem_fun (*this, &RCOptionEditor::ltc_generator_volume_changed));
1636         _ltc_volume_slider = new HSliderOption("ltcvol", _("LTC generator level"), *_ltc_volume_adjustment);
1637
1638         Gtkmm2ext::UI::instance()->set_tip
1639                 (_ltc_volume_slider->tip_widget(),
1640                  _("Specify the Peak Volume of the generated LTC signal in dbFS. A good value is  0dBu ^= -18dbFS in an EBU calibrated system"));
1641
1642         add_option (_("Transport"), _ltc_volume_slider);
1643         parameter_changed ("send-ltc");
1644
1645         parameter_changed ("sync-source");
1646
1647         /* EDITOR */
1648
1649         add_option (S_("Editor"),
1650              new BoolOption (
1651                      "draggable-playhead",
1652                      _("Allow dragging of playhead"),
1653                      sigc::mem_fun (*ARDOUR_UI::config(), &UIConfiguration::get_draggable_playhead),
1654                      sigc::mem_fun (*ARDOUR_UI::config(), &UIConfiguration::set_draggable_playhead)
1655                      ));
1656
1657         add_option (_("Editor"),
1658              new BoolOption (
1659                      "automation-follows-regions",
1660                      _("Move relevant automation when audio regions are moved"),
1661                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_follows_regions),
1662                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_follows_regions)
1663                      ));
1664
1665         add_option (_("Editor"),
1666              new BoolOption (
1667                      "show-track-meters",
1668                      _("Show meters on tracks in the editor"),
1669                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_show_track_meters),
1670                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_show_track_meters)
1671                      ));
1672
1673         add_option (_("Editor"),
1674              new BoolOption (
1675                      "show-editor-meter",
1676                      _("Display master-meter in the toolbar"),
1677                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_show_editor_meter),
1678                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_show_editor_meter)
1679                      ));
1680
1681         ComboOption<FadeShape>* fadeshape = new ComboOption<FadeShape> (
1682                         "default-fade-shape",
1683                         _("Default fade shape"),
1684                         sigc::mem_fun (*_rc_config,
1685                                 &RCConfiguration::get_default_fade_shape),
1686                         sigc::mem_fun (*_rc_config,
1687                                 &RCConfiguration::set_default_fade_shape)
1688                         );
1689
1690         fadeshape->add (FadeLinear,
1691                         _("Linear (for highly correlated material)"));
1692         fadeshape->add (FadeConstantPower, _("Constant power"));
1693         fadeshape->add (FadeSymmetric, _("Symmetric"));
1694         fadeshape->add (FadeSlow, _("Slow"));
1695         fadeshape->add (FadeFast, _("Fast"));
1696
1697         add_option (_("Editor"), fadeshape);
1698
1699
1700         bco = new BoolComboOption (
1701                      "use-overlap-equivalency",
1702                      _("Regions in active edit groups are edited together"),
1703                      _("whenever they overlap in time"),
1704                      _("only if they have identical length, position and origin"),
1705                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_use_overlap_equivalency),
1706                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_use_overlap_equivalency)
1707                      );
1708
1709         add_option (_("Editor"), bco);
1710
1711         ComboOption<LayerModel>* lm = new ComboOption<LayerModel> (
1712                 "layer-model",
1713                 _("Layering model"),
1714                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_layer_model),
1715                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_layer_model)
1716                 );
1717
1718         lm->add (LaterHigher, _("later is higher"));
1719         lm->add (Manual, _("manual layering"));
1720         add_option (_("Editor"), lm);
1721
1722         add_option (_("Editor"),
1723              new BoolOption (
1724                      "rubberbanding-snaps-to-grid",
1725                      _("Make rubberband selection rectangle snap to the grid"),
1726                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_rubberbanding_snaps_to_grid),
1727                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_rubberbanding_snaps_to_grid)
1728                      ));
1729
1730         add_option (_("Editor"),
1731              new BoolOption (
1732                      "show-waveforms",
1733                      _("Show waveforms in regions"),
1734                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_show_waveforms),
1735                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_show_waveforms)
1736                      ));
1737
1738         add_option (_("Editor"),
1739              new BoolComboOption (
1740                      "show-region-gain-envelopes",
1741                      _("Show gain envelopes in audio regions"),
1742                      _("in all modes"),
1743                      _("only in region gain mode"),
1744                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_show_region_gain),
1745                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_show_region_gain)
1746                      ));
1747
1748         ComboOption<WaveformScale>* wfs = new ComboOption<WaveformScale> (
1749                 "waveform-scale",
1750                 _("Waveform scale"),
1751                 sigc::mem_fun (*_ui_config, &UIConfiguration::get_waveform_scale),
1752                 sigc::mem_fun (*_ui_config, &UIConfiguration::set_waveform_scale)
1753                 );
1754
1755         wfs->add (Linear, _("linear"));
1756         wfs->add (Logarithmic, _("logarithmic"));
1757
1758         add_option (_("Editor"), wfs);
1759
1760         ComboOption<WaveformShape>* wfsh = new ComboOption<WaveformShape> (
1761                 "waveform-shape",
1762                 _("Waveform shape"),
1763                 sigc::mem_fun (*_ui_config, &UIConfiguration::get_waveform_shape),
1764                 sigc::mem_fun (*_ui_config, &UIConfiguration::set_waveform_shape)
1765                 );
1766
1767         wfsh->add (Traditional, _("traditional"));
1768         wfsh->add (Rectified, _("rectified"));
1769
1770         add_option (_("Editor"), wfsh);
1771
1772         add_option (_("Editor"), new ClipLevelOptions (_ui_config));
1773
1774         add_option (_("Editor"),
1775              new BoolOption (
1776                      "show-waveforms-while-recording",
1777                      _("Show waveforms for audio while it is being recorded"),
1778                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_show_waveforms_while_recording),
1779                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_show_waveforms_while_recording)
1780                      ));
1781
1782         add_option (_("Editor"),
1783                     new BoolOption (
1784                             "show-zoom-tools",
1785                             _("Show zoom toolbar"),
1786                             sigc::mem_fun (*_ui_config, &UIConfiguration::get_show_zoom_tools),
1787                             sigc::mem_fun (*_ui_config, &UIConfiguration::set_show_zoom_tools)
1788                             ));
1789
1790         add_option (_("Editor"),
1791                     new BoolOption (
1792                             "update-editor-during-summary-drag",
1793                             _("Update editor window during drags of the summary"),
1794                             sigc::mem_fun (*_ui_config, &UIConfiguration::get_update_editor_during_summary_drag),
1795                             sigc::mem_fun (*_ui_config, &UIConfiguration::set_update_editor_during_summary_drag)
1796                             ));
1797
1798         bo = new BoolOption (
1799                      "name-new-markers",
1800                      _("Name new markers"),
1801                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_name_new_markers),
1802                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_name_new_markers)
1803                 );
1804         
1805         add_option (_("Editor"), bo);
1806         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."
1807                                                                 "\n\nYou can always rename markers by right-clicking on them"));
1808
1809         add_option (_("Editor"),
1810             new BoolOption (
1811                     "autoscroll-editor",
1812                     _("Auto-scroll editor window when dragging near its edges"),
1813                     sigc::mem_fun (*_ui_config, &UIConfiguration::get_autoscroll_editor),
1814                     sigc::mem_fun (*_ui_config, &UIConfiguration::set_autoscroll_editor)
1815                     ));
1816
1817         ComboOption<RegionSelectionAfterSplit> *rsas = new ComboOption<RegionSelectionAfterSplit> (
1818                     "region-selection-after-split",
1819                     _("After splitting selected regions, select"),
1820                     sigc::mem_fun (*_rc_config, &RCConfiguration::get_region_selection_after_split),
1821                     sigc::mem_fun (*_rc_config, &RCConfiguration::set_region_selection_after_split));
1822
1823         // TODO: decide which of these modes are really useful
1824         rsas->add(None, _("no regions"));
1825         // rsas->add(NewlyCreatedLeft, _("newly-created regions before the split"));
1826         // rsas->add(NewlyCreatedRight, _("newly-created regions after the split"));
1827         rsas->add(NewlyCreatedBoth, _("newly-created regions"));
1828         // rsas->add(Existing, _("unmodified regions in the existing selection"));
1829         // rsas->add(ExistingNewlyCreatedLeft, _("existing selection and newly-created regions before the split"));
1830         // rsas->add(ExistingNewlyCreatedRight, _("existing selection and newly-created regions after the split"));
1831         rsas->add(ExistingNewlyCreatedBoth, _("existing selection and newly-created regions"));
1832
1833         add_option (_("Editor"), rsas);
1834
1835
1836         /* AUDIO */
1837
1838         add_option (_("Audio"), new OptionEditorHeading (_("Buffering")));
1839
1840         add_option (_("Audio"), new BufferingOptions (_rc_config));
1841
1842         add_option (_("Audio"), new OptionEditorHeading (_("Monitoring")));
1843
1844         ComboOption<MonitorModel>* mm = new ComboOption<MonitorModel> (
1845                 "monitoring-model",
1846                 _("Record monitoring handled by"),
1847                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_monitoring_model),
1848                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_monitoring_model)
1849                 );
1850
1851         if (AudioEngine::instance()->port_engine().can_monitor_input()) {
1852                 mm->add (HardwareMonitoring, _("via Audio Driver"));
1853         }
1854
1855         string prog (PROGRAM_NAME);
1856         boost::algorithm::to_lower (prog);
1857         mm->add (SoftwareMonitoring, string_compose (_("%1"), prog));
1858         mm->add (ExternalMonitoring, _("audio hardware"));
1859
1860         add_option (_("Audio"), mm);
1861
1862         add_option (_("Audio"),
1863              new BoolOption (
1864                      "tape-machine-mode",
1865                      _("Tape machine mode"),
1866                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_tape_machine_mode),
1867                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_tape_machine_mode)
1868                      ));
1869
1870         add_option (_("Audio"), new OptionEditorHeading (_("Connection of tracks and busses")));
1871
1872         add_option (_("Audio"),
1873                     new BoolOption (
1874                             "auto-connect-standard-busses",
1875                             _("Auto-connect master/monitor busses"),
1876                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_connect_standard_busses),
1877                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_connect_standard_busses)
1878                             ));
1879
1880         ComboOption<AutoConnectOption>* iac = new ComboOption<AutoConnectOption> (
1881                 "input-auto-connect",
1882                 _("Connect track inputs"),
1883                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_input_auto_connect),
1884                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_input_auto_connect)
1885                 );
1886
1887         iac->add (AutoConnectPhysical, _("automatically to physical inputs"));
1888         iac->add (ManualConnect, _("manually"));
1889
1890         add_option (_("Audio"), iac);
1891
1892         ComboOption<AutoConnectOption>* oac = new ComboOption<AutoConnectOption> (
1893                 "output-auto-connect",
1894                 _("Connect track and bus outputs"),
1895                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_output_auto_connect),
1896                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_output_auto_connect)
1897                 );
1898
1899         oac->add (AutoConnectPhysical, _("automatically to physical outputs"));
1900         oac->add (AutoConnectMaster, _("automatically to master bus"));
1901         oac->add (ManualConnect, _("manually"));
1902
1903         add_option (_("Audio"), oac);
1904
1905         add_option (_("Audio"), new OptionEditorHeading (_("Denormals")));
1906
1907         add_option (_("Audio"),
1908              new BoolOption (
1909                      "denormal-protection",
1910                      _("Use DC bias to protect against denormals"),
1911                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_protection),
1912                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_protection)
1913                      ));
1914
1915         ComboOption<DenormalModel>* dm = new ComboOption<DenormalModel> (
1916                 "denormal-model",
1917                 _("Processor handling"),
1918                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_model),
1919                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_model)
1920                 );
1921
1922         int dmsize = 1;
1923         dm->add (DenormalNone, _("no processor handling"));
1924
1925         FPU fpu;
1926
1927         if (fpu.has_flush_to_zero()) {
1928                 ++dmsize;
1929                 dm->add (DenormalFTZ, _("use FlushToZero"));
1930         } else if (_rc_config->get_denormal_model() == DenormalFTZ) {
1931                 _rc_config->set_denormal_model(DenormalNone);
1932         }
1933
1934         if (fpu.has_denormals_are_zero()) {
1935                 ++dmsize;
1936                 dm->add (DenormalDAZ, _("use DenormalsAreZero"));
1937         } else if (_rc_config->get_denormal_model() == DenormalDAZ) {
1938                 _rc_config->set_denormal_model(DenormalNone);
1939         }
1940
1941         if (fpu.has_flush_to_zero() && fpu.has_denormals_are_zero()) {
1942                 ++dmsize;
1943                 dm->add (DenormalFTZDAZ, _("use FlushToZero and DenormalsAreZero"));
1944         } else if (_rc_config->get_denormal_model() == DenormalFTZDAZ) {
1945                 _rc_config->set_denormal_model(DenormalNone);
1946         }
1947
1948         if (dmsize == 1) {
1949                 dm->set_sensitive(false);
1950         }
1951
1952         add_option (_("Audio"), dm);
1953
1954         add_option (_("Audio"), new OptionEditorHeading (_("Plugins")));
1955
1956         add_option (_("Audio"),
1957              new BoolOption (
1958                      "plugins-stop-with-transport",
1959                      _("Silence plugins when the transport is stopped"),
1960                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugins_stop_with_transport),
1961                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_plugins_stop_with_transport)
1962                      ));
1963
1964         add_option (_("Audio"),
1965              new BoolOption (
1966                      "new-plugins-active",
1967                      _("Make new plugins active"),
1968                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_new_plugins_active),
1969                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_new_plugins_active)
1970                      ));
1971
1972         add_option (_("Audio"), new OptionEditorHeading (_("Regions")));
1973
1974         add_option (_("Audio"),
1975              new BoolOption (
1976                      "auto-analyse-audio",
1977                      _("Enable automatic analysis of audio"),
1978                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_analyse_audio),
1979                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_analyse_audio)
1980                      ));
1981
1982         add_option (_("Audio"),
1983              new BoolOption (
1984                      "replicate-missing-region-channels",
1985                      _("Replicate missing region channels"),
1986                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_replicate_missing_region_channels),
1987                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_replicate_missing_region_channels)
1988                      ));
1989
1990         /* SOLO AND MUTE */
1991
1992         add_option (_("Solo / mute"), new OptionEditorHeading (_("Solo")));
1993
1994         add_option (_("Solo / mute"),
1995              new FaderOption (
1996                      "solo-mute-gain",
1997                      _("Solo-in-place mute cut (dB)"),
1998                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_gain),
1999                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_gain)
2000                      ));
2001
2002         _solo_control_is_listen_control = new BoolOption (
2003                 "solo-control-is-listen-control",
2004                 _("Solo controls are Listen controls"),
2005                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_control_is_listen_control),
2006                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_control_is_listen_control)
2007                 );
2008
2009         add_option (_("Solo / mute"), _solo_control_is_listen_control);
2010
2011         _listen_position = new ComboOption<ListenPosition> (
2012                 "listen-position",
2013                 _("Listen Position"),
2014                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_listen_position),
2015                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_listen_position)
2016                 );
2017
2018         _listen_position->add (AfterFaderListen, _("after-fader (AFL)"));
2019         _listen_position->add (PreFaderListen, _("pre-fader (PFL)"));
2020
2021         add_option (_("Solo / mute"), _listen_position);
2022
2023         ComboOption<PFLPosition>* pp = new ComboOption<PFLPosition> (
2024                 "pfl-position",
2025                 _("PFL signals come from"),
2026                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_pfl_position),
2027                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_pfl_position)
2028                 );
2029
2030         pp->add (PFLFromBeforeProcessors, _("before pre-fader processors"));
2031         pp->add (PFLFromAfterProcessors, _("pre-fader but after pre-fader processors"));
2032
2033         add_option (_("Solo / mute"), pp);
2034
2035         ComboOption<AFLPosition>* pa = new ComboOption<AFLPosition> (
2036                 "afl-position",
2037                 _("AFL signals come from"),
2038                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_afl_position),
2039                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_afl_position)
2040                 );
2041
2042         pa->add (AFLFromBeforeProcessors, _("immediately post-fader"));
2043         pa->add (AFLFromAfterProcessors, _("after post-fader processors (before pan)"));
2044
2045         add_option (_("Solo / mute"), pa);
2046
2047         parameter_changed ("use-monitor-bus");
2048
2049         add_option (_("Solo / mute"),
2050              new BoolOption (
2051                      "exclusive-solo",
2052                      _("Exclusive solo"),
2053                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_exclusive_solo),
2054                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_exclusive_solo)
2055                      ));
2056
2057         add_option (_("Solo / mute"),
2058              new BoolOption (
2059                      "show-solo-mutes",
2060                      _("Show solo muting"),
2061                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_show_solo_mutes),
2062                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_solo_mutes)
2063                      ));
2064
2065         add_option (_("Solo / mute"),
2066              new BoolOption (
2067                      "solo-mute-override",
2068                      _("Soloing overrides muting"),
2069                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_override),
2070                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_override)
2071                      ));
2072
2073         add_option (_("Solo / mute"), new OptionEditorHeading (_("Default track / bus muting options")));
2074
2075         add_option (_("Solo / mute"),
2076              new BoolOption (
2077                      "mute-affects-pre-fader",
2078                      _("Mute affects pre-fader sends"),
2079                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_pre_fader),
2080                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_pre_fader)
2081                      ));
2082
2083         add_option (_("Solo / mute"),
2084              new BoolOption (
2085                      "mute-affects-post-fader",
2086                      _("Mute affects post-fader sends"),
2087                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_post_fader),
2088                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_post_fader)
2089                      ));
2090
2091         add_option (_("Solo / mute"),
2092              new BoolOption (
2093                      "mute-affects-control-outs",
2094                      _("Mute affects control outputs"),
2095                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_control_outs),
2096                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_control_outs)
2097                      ));
2098
2099         add_option (_("Solo / mute"),
2100              new BoolOption (
2101                      "mute-affects-main-outs",
2102                      _("Mute affects main outputs"),
2103                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_main_outs),
2104                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_main_outs)
2105                      ));
2106
2107         add_option (_("Solo / mute"), new OptionEditorHeading (_("Send Routing")));
2108
2109         add_option (_("Solo / mute"),
2110              new BoolOption (
2111                      "link-send-and-route-panner",
2112                      _("Link panners of Aux and External Sends with main panner by default"),
2113                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_link_send_and_route_panner),
2114                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_link_send_and_route_panner)
2115                      ));
2116
2117         add_option (_("MIDI"),
2118                     new SpinOption<float> (
2119                             "midi-readahead",
2120                             _("MIDI read-ahead time (seconds)"),
2121                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_readahead),
2122                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_readahead),
2123                             0.1, 10, 0.1, 1,
2124                             "", 1.0, 1
2125                             ));
2126
2127         add_option (_("MIDI"),
2128                     new BoolOption (
2129                             "send-midi-clock",
2130                             _("Send MIDI Clock"),
2131                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_midi_clock),
2132                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_midi_clock)
2133                             ));
2134
2135         add_option (_("MIDI"),
2136                     new BoolOption (
2137                             "send-mtc",
2138                             _("Send MIDI Time Code"),
2139                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mtc),
2140                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mtc)
2141                             ));
2142
2143         add_option (_("MIDI"),
2144                     new SpinOption<int> (
2145                             "mtc-qf-speed-tolerance",
2146                             _("Percentage either side of normal transport speed to transmit MTC"),
2147                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mtc_qf_speed_tolerance),
2148                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mtc_qf_speed_tolerance),
2149                             0, 20, 1, 5
2150                             ));
2151
2152         add_option (_("MIDI"),
2153                     new BoolOption (
2154                             "mmc-control",
2155                             _("Obey MIDI Machine Control commands"),
2156                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_control),
2157                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_control)
2158                             ));
2159
2160         add_option (_("MIDI"),
2161                     new BoolOption (
2162                             "send-mmc",
2163                             _("Send MIDI Machine Control commands"),
2164                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mmc),
2165                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mmc)
2166                             ));
2167
2168         add_option (_("MIDI"),
2169                     new BoolOption (
2170                             "midi-feedback",
2171                             _("Send MIDI control feedback"),
2172                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_feedback),
2173                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_feedback)
2174                             ));
2175
2176         add_option (_("MIDI"),
2177              new SpinOption<uint8_t> (
2178                      "mmc-receive-device-id",
2179                      _("Inbound MMC device ID"),
2180                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_receive_device_id),
2181                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_receive_device_id),
2182                      0, 128, 1, 10
2183                      ));
2184
2185         add_option (_("MIDI"),
2186              new SpinOption<uint8_t> (
2187                      "mmc-send-device-id",
2188                      _("Outbound MMC device ID"),
2189                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_send_device_id),
2190                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_send_device_id),
2191                      0, 128, 1, 10
2192                      ));
2193
2194         add_option (_("MIDI"),
2195              new SpinOption<int32_t> (
2196                      "initial-program-change",
2197                      _("Initial program change"),
2198                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_initial_program_change),
2199                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_initial_program_change),
2200                      -1, 65536, 1, 10
2201                      ));
2202
2203         add_option (_("MIDI"),
2204                     new BoolOption (
2205                             "display-first-midi-bank-as-zero",
2206                             _("Display first MIDI bank/program as 0"),
2207                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_first_midi_bank_is_zero),
2208                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_first_midi_bank_is_zero)
2209                             ));
2210
2211         add_option (_("MIDI"),
2212              new BoolOption (
2213                      "never-display-periodic-midi",
2214                      _("Never display periodic MIDI messages (MTC, MIDI Clock)"),
2215                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_never_display_periodic_midi),
2216                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_never_display_periodic_midi)
2217                      ));
2218
2219         add_option (_("MIDI"),
2220              new BoolOption (
2221                      "sound-midi-notes",
2222                      _("Sound MIDI notes as they are selected"),
2223                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_sound_midi_notes),
2224                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_sound_midi_notes)
2225                      ));
2226
2227         add_option (_("MIDI"), new OptionEditorHeading (_("Midi Audition")));
2228
2229         ComboOption<std::string>* audition_synth = new ComboOption<std::string> (
2230                 "midi-audition-synth-uri",
2231                 _("Midi Audition Synth (LV2)"),
2232                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_audition_synth_uri),
2233                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_audition_synth_uri)
2234                 );
2235
2236         audition_synth->add(X_(""), _("None"));
2237         PluginInfoList all_plugs;
2238         PluginManager& manager (PluginManager::instance());
2239 #ifdef LV2_SUPPORT
2240         all_plugs.insert (all_plugs.end(), manager.lv2_plugin_info().begin(), manager.lv2_plugin_info().end());
2241
2242         for (PluginInfoList::const_iterator i = all_plugs.begin(); i != all_plugs.end(); ++i) {
2243                 if (manager.get_status (*i) == PluginManager::Hidden) continue;
2244                 if (!(*i)->is_instrument()) continue;
2245                 if ((*i)->type != ARDOUR::LV2) continue;
2246                 audition_synth->add((*i)->unique_id, (*i)->name);
2247         }
2248 #endif
2249
2250         add_option (_("MIDI"), audition_synth);
2251
2252         /* USER INTERACTION */
2253
2254         if (
2255 #ifdef PLATFORM_WINDOWS
2256                         true
2257 #else
2258                         getenv ("ARDOUR_BUNDLED")
2259 #endif
2260            )
2261         {
2262                 add_option (_("User interaction"), 
2263                             new BoolOption (
2264                                     "enable-translation",
2265                                     string_compose (_("Use translations of %1 messages\n"
2266                                                       "   <i>(requires a restart of %1 to take effect)</i>\n"
2267                                                       "   <i>(if available for your language preferences)</i>"), PROGRAM_NAME),
2268                                     sigc::ptr_fun (ARDOUR::translations_are_enabled),
2269                                     sigc::ptr_fun (ARDOUR::set_translations_enabled)));
2270         }
2271
2272         add_option (_("User interaction"), new OptionEditorHeading (_("Keyboard")));
2273
2274         add_option (_("User interaction"), new KeyboardOptions);
2275
2276         /* Control Surfaces */
2277
2278         add_option (_("Control Surfaces"), new ControlSurfacesOptions (*this));
2279
2280         ComboOption<RemoteModel>* rm = new ComboOption<RemoteModel> (
2281                 "remote-model",
2282                 _("Control surface remote ID"),
2283                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_remote_model),
2284                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_remote_model)
2285                 );
2286
2287         rm->add (UserOrdered, _("assigned by user"));
2288         rm->add (MixerOrdered, _("follows order of mixer"));
2289
2290         add_option (_("Control Surfaces"), rm);
2291
2292         /* VIDEO Timeline */
2293         add_option (_("Video"), new VideoTimelineOptions (_rc_config));
2294
2295 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined AUDIOUNIT_SUPPORT)
2296         /* Plugin options (currrently VST only) */
2297         add_option (_("Plugins"), new PluginOptions (_rc_config, _ui_config));
2298 #endif
2299
2300         /* INTERFACE */
2301
2302         add_option (S_("Preferences|GUI"),
2303              new BoolOption (
2304                      "widget-prelight",
2305                      _("Graphically indicate mouse pointer hovering over various widgets"),
2306                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_widget_prelight),
2307                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_widget_prelight)
2308                      ));
2309
2310 #ifdef TOOLTIPS_GOT_FIXED
2311         add_option (S_("Preferences|GUI"),
2312              new BoolOption (
2313                      "use-tooltips",
2314                      _("Show tooltips if mouse hovers over a control"),
2315                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_use_tooltips),
2316                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_use_tooltips)
2317                      ));
2318 #endif
2319
2320         add_option (S_("Preferences|GUI"),
2321              new BoolOption (
2322                      "show-name-highlight",
2323                      _("Use name highlight bars in region displays (requires a restart)"),
2324                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_show_name_highlight),
2325                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_show_name_highlight)
2326                      ));
2327
2328 #ifndef GTKOSX
2329         /* font scaling does nothing with GDK/Quartz */
2330         add_option (S_("Preferences|GUI"), new FontScalingOptions (_ui_config));
2331 #endif
2332
2333         add_option (S_("GUI"),
2334                     new BoolOption (
2335                             "super-rapid-clock-update",
2336                             _("update transport clock display at FPS instead of every 100ms"),
2337                             sigc::mem_fun (*_ui_config, &UIConfiguration::get_super_rapid_clock_update),
2338                             sigc::mem_fun (*_ui_config, &UIConfiguration::set_super_rapid_clock_update)
2339                             ));
2340
2341         /* Lock GUI timeout */
2342
2343         Gtk::Adjustment *lts = manage (new Gtk::Adjustment(0, 0, 1000, 1, 10));
2344         HSliderOption *slts = new HSliderOption("lock-gui-after-seconds",
2345                                                 _("Lock timeout (seconds)"),
2346                                                 lts,
2347                                                 sigc::mem_fun (*ARDOUR_UI::config(), &UIConfiguration::get_lock_gui_after_seconds),
2348                                                 sigc::mem_fun (*ARDOUR_UI::config(), &UIConfiguration::set_lock_gui_after_seconds)
2349                         );
2350         slts->scale().set_digits (0);
2351         Gtkmm2ext::UI::instance()->set_tip
2352                 (slts->tip_widget(),
2353                  _("Lock GUI after this many idle seconds (zero to never lock)"));
2354         add_option (S_("Preferences|GUI"), slts);
2355
2356         /* The names of these controls must be the same as those given in MixerStrip
2357            for the actual widgets being controlled.
2358         */
2359         _mixer_strip_visibility.add (0, X_("Input"), _("Input"));
2360         _mixer_strip_visibility.add (0, X_("PhaseInvert"), _("Phase Invert"));
2361         _mixer_strip_visibility.add (0, X_("RecMon"), _("Record & Monitor"));
2362         _mixer_strip_visibility.add (0, X_("SoloIsoLock"), _("Solo Iso / Lock"));
2363         _mixer_strip_visibility.add (0, X_("Output"), _("Output"));
2364         _mixer_strip_visibility.add (0, X_("Comments"), _("Comments"));
2365         
2366         add_option (
2367                 S_("Preferences|GUI"),
2368                 new VisibilityOption (
2369                         _("Mixer Strip"),
2370                         &_mixer_strip_visibility,
2371                         sigc::mem_fun (*_ui_config, &UIConfiguration::get_mixer_strip_visibility),
2372                         sigc::mem_fun (*_ui_config, &UIConfiguration::set_mixer_strip_visibility)
2373                         )
2374                 );
2375
2376         add_option (S_("Preferences|GUI"),
2377              new BoolOption (
2378                      "default-narrow_ms",
2379                      _("Use narrow strips in the mixer by default"),
2380                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_default_narrow_ms),
2381                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_default_narrow_ms)
2382                      ));
2383
2384         add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Metering")));
2385
2386         ComboOption<float>* mht = new ComboOption<float> (
2387                 "meter-hold",
2388                 _("Peak hold time"),
2389                 sigc::mem_fun (*_ui_config, &UIConfiguration::get_meter_hold),
2390                 sigc::mem_fun (*_ui_config, &UIConfiguration::set_meter_hold)
2391                 );
2392
2393         mht->add (MeterHoldOff, _("off"));
2394         mht->add (MeterHoldShort, _("short"));
2395         mht->add (MeterHoldMedium, _("medium"));
2396         mht->add (MeterHoldLong, _("long"));
2397
2398         add_option (S_("Preferences|Metering"), mht);
2399
2400         ComboOption<float>* mfo = new ComboOption<float> (
2401                 "meter-falloff",
2402                 _("DPM fall-off"),
2403                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_falloff),
2404                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_falloff)
2405                 );
2406
2407         mfo->add (METER_FALLOFF_OFF,      _("off"));
2408         mfo->add (METER_FALLOFF_SLOWEST,  _("slowest [6.6dB/sec]"));
2409         mfo->add (METER_FALLOFF_SLOW,     _("slow [8.6dB/sec] (BBC PPM, EBU PPM)"));
2410         mfo->add (METER_FALLOFF_SLOWISH,  _("slowish [12.0dB/sec] (DIN)"));
2411         mfo->add (METER_FALLOFF_MODERATE, _("moderate [13.3dB/sec] (EBU Digi PPM, IRT Digi PPM)"));
2412         mfo->add (METER_FALLOFF_MEDIUM,   _("medium [20dB/sec]"));
2413         mfo->add (METER_FALLOFF_FAST,     _("fast [32dB/sec]"));
2414         mfo->add (METER_FALLOFF_FASTER,   _("faster [46dB/sec]"));
2415         mfo->add (METER_FALLOFF_FASTEST,  _("fastest [70dB/sec]"));
2416
2417         add_option (S_("Preferences|Metering"), mfo);
2418
2419         ComboOption<MeterLineUp>* mlu = new ComboOption<MeterLineUp> (
2420                 "meter-line-up-level",
2421                 _("Meter line-up level; 0dBu"),
2422                 sigc::mem_fun (*_ui_config, &UIConfiguration::get_meter_line_up_level),
2423                 sigc::mem_fun (*_ui_config, &UIConfiguration::set_meter_line_up_level)
2424                 );
2425
2426         mlu->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
2427         mlu->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
2428         mlu->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
2429         mlu->add (MeteringLineUp15, _("-15dBFS (DIN)"));
2430
2431         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."));
2432
2433         add_option (S_("Preferences|Metering"), mlu);
2434
2435         ComboOption<MeterLineUp>* mld = new ComboOption<MeterLineUp> (
2436                 "meter-line-up-din",
2437                 _("IEC1/DIN Meter line-up level; 0dBu"),
2438                 sigc::mem_fun (*_ui_config, &UIConfiguration::get_meter_line_up_din),
2439                 sigc::mem_fun (*_ui_config, &UIConfiguration::set_meter_line_up_din)
2440                 );
2441
2442         mld->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
2443         mld->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
2444         mld->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
2445         mld->add (MeteringLineUp15, _("-15dBFS (DIN)"));
2446
2447         Gtkmm2ext::UI::instance()->set_tip (mld->tip_widget(), _("Reference level for IEC1/DIN meter."));
2448
2449         add_option (S_("Preferences|Metering"), mld);
2450
2451         ComboOption<VUMeterStandard>* mvu = new ComboOption<VUMeterStandard> (
2452                 "meter-vu-standard",
2453                 _("VU Meter standard"),
2454                 sigc::mem_fun (*_ui_config, &UIConfiguration::get_meter_vu_standard),
2455                 sigc::mem_fun (*_ui_config, &UIConfiguration::set_meter_vu_standard)
2456                 );
2457
2458         mvu->add (MeteringVUfrench,   _("0VU = -2dBu (France)"));
2459         mvu->add (MeteringVUamerican, _("0VU = 0dBu (North America, Australia)"));
2460         mvu->add (MeteringVUstandard, _("0VU = +4dBu (standard)"));
2461         mvu->add (MeteringVUeight,    _("0VU = +8dBu"));
2462
2463         add_option (S_("Preferences|Metering"), mvu);
2464
2465         Gtk::Adjustment *mpk = manage (new Gtk::Adjustment(0, -10, 0, .1, .1));
2466         HSliderOption *mpks = new HSliderOption("meter-peak",
2467                         _("Peak threshold [dBFS]"),
2468                         mpk,
2469                         sigc::mem_fun (*_ui_config, &UIConfiguration::get_meter_peak),
2470                         sigc::mem_fun (*_ui_config, &UIConfiguration::set_meter_peak)
2471                         );
2472
2473         Gtkmm2ext::UI::instance()->set_tip
2474                 (mpks->tip_widget(),
2475                  _("Specify the audio signal level in dbFS at and above which the meter-peak indicator will flash red."));
2476
2477         add_option (S_("Preferences|Metering"), mpks);
2478
2479         add_option (S_("Preferences|Metering"),
2480              new BoolOption (
2481                      "meter-style-led",
2482                      _("LED meter style"),
2483                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_meter_style_led),
2484                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_meter_style_led)
2485                      ));
2486
2487         /* and now the theme manager */
2488
2489         ThemeManager* tm = manage (new ThemeManager);
2490         add_page (_("Theme"), *tm);
2491 }
2492
2493 void
2494 RCOptionEditor::parameter_changed (string const & p)
2495 {
2496         OptionEditor::parameter_changed (p);
2497
2498         if (p == "use-monitor-bus") {
2499                 bool const s = Config->get_use_monitor_bus ();
2500                 if (!s) {
2501                         /* we can't use this if we don't have a monitor bus */
2502                         Config->set_solo_control_is_listen_control (false);
2503                 }
2504                 _solo_control_is_listen_control->set_sensitive (s);
2505                 _listen_position->set_sensitive (s);
2506         } else if (p == "sync-source") {
2507                 _sync_source->set_sensitive (true);
2508                 if (_session) {
2509                         _sync_source->set_sensitive (!_session->config.get_external_sync());
2510                 }
2511                 switch(Config->get_sync_source()) {
2512                 case ARDOUR::MTC:
2513                 case ARDOUR::LTC:
2514                         _sync_genlock->set_sensitive (true);
2515                         _sync_framerate->set_sensitive (true);
2516                         _sync_source_2997->set_sensitive (true);
2517                         break;
2518                 default:
2519                         _sync_genlock->set_sensitive (false);
2520                         _sync_framerate->set_sensitive (false);
2521                         _sync_source_2997->set_sensitive (false);
2522                         break;
2523                 }
2524         } else if (p == "send-ltc") {
2525                 bool const s = Config->get_send_ltc ();
2526                 _ltc_send_continuously->set_sensitive (s);
2527                 _ltc_volume_slider->set_sensitive (s);
2528         }
2529 }
2530
2531 void RCOptionEditor::ltc_generator_volume_changed () {
2532         _rc_config->set_ltc_output_volume (pow(10, _ltc_volume_adjustment->get_value() / 20));
2533 }
2534
2535 void
2536 RCOptionEditor::populate_sync_options ()
2537 {
2538         vector<SyncSource> sync_opts = ARDOUR::get_available_sync_options ();
2539
2540         _sync_source->clear ();
2541
2542         for (vector<SyncSource>::iterator i = sync_opts.begin(); i != sync_opts.end(); ++i) {
2543                 _sync_source->add (*i, sync_source_to_string (*i));
2544         }
2545
2546         if (sync_opts.empty()) {
2547                 _sync_source->set_sensitive(false);
2548         } else {
2549                 if (std::find(sync_opts.begin(), sync_opts.end(), _rc_config->get_sync_source()) == sync_opts.end()) {
2550                         _rc_config->set_sync_source(sync_opts.front());
2551                 }
2552         }
2553 }