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