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