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