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