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