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