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