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