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