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