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