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