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