use new FPU singleton pattern in gtk2_ardour
[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                 _playback_adjustment.set_value (_rc_config->get_audio_playback_buffer_seconds());
1158
1159                 Label* l = manage (new Label (_("Playback (seconds of buffering):")));
1160                 l->set_name ("OptionsLabel");
1161
1162                 _playback_slider.set_update_policy (UPDATE_DISCONTINUOUS);
1163                 HBox* h = manage (new HBox);
1164                 h->set_spacing (4);
1165                 h->pack_start (*l, false, false);
1166                 h->pack_start (_playback_slider, true, true);
1167
1168                 _box->pack_start (*h, false, false);
1169
1170                 _capture_adjustment.set_value (_rc_config->get_audio_capture_buffer_seconds());
1171
1172                 l = manage (new Label (_("Recording (seconds of buffering):")));
1173                 l->set_name ("OptionsLabel");
1174
1175                 _capture_slider.set_update_policy (UPDATE_DISCONTINUOUS);
1176                 h = manage (new HBox);
1177                 h->set_spacing (4);
1178                 h->pack_start (*l, false, false);
1179                 h->pack_start (_capture_slider, true, true);
1180
1181                 _box->pack_start (*h, false, false);
1182
1183                 _capture_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &BufferingOptions::capture_changed));
1184                 _playback_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &BufferingOptions::playback_changed));
1185         }
1186
1187         void parameter_changed (string const & p)
1188         {
1189                 if (p == "playback-buffer-seconds") {
1190                         _playback_adjustment.set_value (_rc_config->get_audio_playback_buffer_seconds());
1191                 } else if (p == "capture-buffer-seconds") {
1192                         _capture_adjustment.set_value (_rc_config->get_audio_capture_buffer_seconds());
1193                 }
1194         }
1195
1196         void set_state_from_config ()
1197         {
1198                 parameter_changed ("playback-buffer-seconds");
1199                 parameter_changed ("capture-buffer-seconds");
1200         }
1201
1202 private:
1203
1204         void playback_changed ()
1205         {
1206                 _rc_config->set_audio_playback_buffer_seconds ((long) _playback_adjustment.get_value());
1207         }
1208
1209         void capture_changed ()
1210         {
1211                 _rc_config->set_audio_capture_buffer_seconds ((long) _capture_adjustment.get_value());
1212         }
1213
1214         RCConfiguration* _rc_config;
1215         Adjustment _playback_adjustment;
1216         Adjustment _capture_adjustment;
1217         HScale _playback_slider;
1218         HScale _capture_slider;
1219 };
1220
1221 class ControlSurfacesOptions : public OptionEditorBox
1222 {
1223 public:
1224         ControlSurfacesOptions (Gtk::Window& parent)
1225                 : _parent (parent)
1226                 , _ignore_view_change (0)
1227         {
1228                 _store = ListStore::create (_model);
1229                 _view.set_model (_store);
1230                 _view.append_column (_("Control Surface Protocol"), _model.name);
1231                 _view.get_column(0)->set_resizable (true);
1232                 _view.get_column(0)->set_expand (true);
1233                 _view.append_column_editable (_("Enabled"), _model.enabled);
1234                 _view.append_column_editable (_("Feedback"), _model.feedback);
1235
1236                 _box->pack_start (_view, false, false);
1237
1238                 Label* label = manage (new Label);
1239                 label->set_markup (string_compose (X_("<i>%1</i>"), _("Double-click on a name to edit settings for an enabled protocol")));
1240
1241                 _box->pack_start (*label, false, false);
1242                 label->show ();
1243
1244                 ControlProtocolManager& m = ControlProtocolManager::instance ();
1245                 m.ProtocolStatusChange.connect (protocol_status_connection, MISSING_INVALIDATOR,
1246                                                 boost::bind (&ControlSurfacesOptions::protocol_status_changed, this, _1), gui_context());
1247
1248                 _store->signal_row_changed().connect (sigc::mem_fun (*this, &ControlSurfacesOptions::view_changed));
1249                 _view.signal_button_press_event().connect_notify (sigc::mem_fun(*this, &ControlSurfacesOptions::edit_clicked));
1250         }
1251
1252         void parameter_changed (std::string const &)
1253         {
1254
1255         }
1256
1257         void set_state_from_config ()
1258         {
1259                 _store->clear ();
1260
1261                 ControlProtocolManager& m = ControlProtocolManager::instance ();
1262                 for (list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
1263
1264                         if (!(*i)->mandatory) {
1265                                 TreeModel::Row r = *_store->append ();
1266                                 r[_model.name] = (*i)->name;
1267                                 r[_model.enabled] = ((*i)->protocol || (*i)->requested);
1268                                 r[_model.feedback] = ((*i)->protocol && (*i)->protocol->get_feedback ());
1269                                 r[_model.protocol_info] = *i;
1270                         }
1271                 }
1272         }
1273
1274 private:
1275
1276         void protocol_status_changed (ControlProtocolInfo* cpi) {
1277                 /* find the row */
1278                 TreeModel::Children rows = _store->children();
1279                 
1280                 for (TreeModel::Children::iterator x = rows.begin(); x != rows.end(); ++x) {
1281                         string n = ((*x)[_model.name]);
1282
1283                         if ((*x)[_model.protocol_info] == cpi) {
1284                                 _ignore_view_change++;
1285                                 (*x)[_model.enabled] = (cpi->protocol || cpi->requested);
1286                                 _ignore_view_change--;
1287                                 break;
1288                         }
1289                 }
1290         }
1291
1292         void view_changed (TreeModel::Path const &, TreeModel::iterator const & i)
1293         {
1294                 TreeModel::Row r = *i;
1295
1296                 if (_ignore_view_change) {
1297                         return;
1298                 }
1299
1300                 ControlProtocolInfo* cpi = r[_model.protocol_info];
1301                 if (!cpi) {
1302                         return;
1303                 }
1304
1305                 bool const was_enabled = (cpi->protocol != 0);
1306                 bool const is_enabled = r[_model.enabled];
1307
1308
1309                 if (was_enabled != is_enabled) {
1310
1311                         if (!was_enabled) {
1312                                 ControlProtocolManager::instance().activate (*cpi);
1313                         } else {
1314                                 ControlProtocolManager::instance().deactivate (*cpi);
1315                         }
1316                 }
1317
1318                 bool const was_feedback = (cpi->protocol && cpi->protocol->get_feedback ());
1319                 bool const is_feedback = r[_model.feedback];
1320
1321                 if (was_feedback != is_feedback && cpi->protocol) {
1322                         cpi->protocol->set_feedback (is_feedback);
1323                 }
1324         }
1325
1326         void edit_clicked (GdkEventButton* ev)
1327         {
1328                 if (ev->type != GDK_2BUTTON_PRESS) {
1329                         return;
1330                 }
1331
1332                 std::string name;
1333                 ControlProtocolInfo* cpi;
1334                 TreeModel::Row row;
1335
1336                 row = *(_view.get_selection()->get_selected());
1337                 if (!row[_model.enabled]) {
1338                         return;
1339                 }
1340                 cpi = row[_model.protocol_info];
1341                 if (!cpi || !cpi->protocol || !cpi->protocol->has_editor ()) {
1342                         return;
1343                 }
1344                 Box* box = (Box*) cpi->protocol->get_gui ();
1345                 if (!box) {
1346                         return;
1347                 }
1348                 if (box->get_parent()) {
1349                         static_cast<ArdourWindow*>(box->get_parent())->present();
1350                         return;
1351                 }
1352                 string title = row[_model.name];
1353                 /* once created, the window is managed by the surface itself (as ->get_parent())
1354                  * Surface's tear_down_gui() is called on session close, when de-activating
1355                  * or re-initializing a surface.
1356                  * tear_down_gui() hides an deletes the Window if it exists.
1357                  */
1358                 ArdourWindow* win = new ArdourWindow (_parent, title);
1359                 win->set_title ("Control Protocol Options");
1360                 win->add (*box);
1361                 box->show ();
1362                 win->present ();
1363         }
1364
1365         class ControlSurfacesModelColumns : public TreeModelColumnRecord
1366         {
1367         public:
1368
1369                 ControlSurfacesModelColumns ()
1370                 {
1371                         add (name);
1372                         add (enabled);
1373                         add (feedback);
1374                         add (protocol_info);
1375                 }
1376
1377                 TreeModelColumn<string> name;
1378                 TreeModelColumn<bool> enabled;
1379                 TreeModelColumn<bool> feedback;
1380                 TreeModelColumn<ControlProtocolInfo*> protocol_info;
1381         };
1382
1383         Glib::RefPtr<ListStore> _store;
1384         ControlSurfacesModelColumns _model;
1385         TreeView _view;
1386         Gtk::Window& _parent;
1387         PBD::ScopedConnection protocol_status_connection;
1388         uint32_t _ignore_view_change;
1389 };
1390
1391 class VideoTimelineOptions : public OptionEditorBox
1392 {
1393 public:
1394         VideoTimelineOptions (RCConfiguration* c)
1395                 : _rc_config (c)
1396                 , _show_video_export_info_button (_("Show Video Export Info before export"))
1397                 , _show_video_server_dialog_button (_("Show Video Server Startup Dialog"))
1398                 , _video_advanced_setup_button (_("Advanced Setup (remote video server)"))
1399         {
1400                 Table* t = manage (new Table (2, 6));
1401                 t->set_spacings (4);
1402
1403                 t->attach (_video_advanced_setup_button, 0, 2, 0, 1);
1404                 _video_advanced_setup_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::video_advanced_setup_toggled));
1405                 Gtkmm2ext::UI::instance()->set_tip (_video_advanced_setup_button,
1406                                             _("<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."));
1407
1408                 Label* l = manage (new Label (_("Video Server URL:")));
1409                 l->set_alignment (0, 0.5);
1410                 t->attach (*l, 0, 1, 1, 2, FILL);
1411                 t->attach (_video_server_url_entry, 1, 2, 1, 2, FILL);
1412                 Gtkmm2ext::UI::instance()->set_tip (_video_server_url_entry,
1413                                             _("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"));
1414
1415                 l = manage (new Label (_("Video Folder:")));
1416                 l->set_alignment (0, 0.5);
1417                 t->attach (*l, 0, 1, 2, 3, FILL);
1418                 t->attach (_video_server_docroot_entry, 1, 2, 2, 3);
1419                 Gtkmm2ext::UI::instance()->set_tip (_video_server_docroot_entry,
1420                                             _("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."));
1421
1422                 /* small vspace  y=3..4 */
1423
1424                 t->attach (_show_video_export_info_button, 0, 2, 4, 5);
1425                 _show_video_export_info_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::show_video_export_info_toggled));
1426                 Gtkmm2ext::UI::instance()->set_tip (_show_video_export_info_button,
1427                                             _("<b>When enabled</b> an information window with details is displayed before the video-export dialog."));
1428
1429                 t->attach (_show_video_server_dialog_button, 0, 2, 5, 6);
1430                 _show_video_server_dialog_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::show_video_server_dialog_toggled));
1431                 Gtkmm2ext::UI::instance()->set_tip (_show_video_server_dialog_button,
1432                                             _("<b>When enabled</b> the video server is never launched automatically without confirmation"));
1433
1434                 _video_server_url_entry.signal_changed().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_url_changed));
1435                 _video_server_url_entry.signal_activate().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_url_changed));
1436                 _video_server_docroot_entry.signal_changed().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_docroot_changed));
1437                 _video_server_docroot_entry.signal_activate().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_docroot_changed));
1438
1439                 _box->pack_start (*t,true,true);
1440         }
1441
1442         void server_url_changed ()
1443         {
1444                 _rc_config->set_video_server_url (_video_server_url_entry.get_text());
1445         }
1446
1447         void server_docroot_changed ()
1448         {
1449                 _rc_config->set_video_server_docroot (_video_server_docroot_entry.get_text());
1450         }
1451
1452         void show_video_export_info_toggled ()
1453         {
1454                 bool const x = _show_video_export_info_button.get_active ();
1455                 _rc_config->set_show_video_export_info (x);
1456         }
1457
1458         void show_video_server_dialog_toggled ()
1459         {
1460                 bool const x = _show_video_server_dialog_button.get_active ();
1461                 _rc_config->set_show_video_server_dialog (x);
1462         }
1463
1464         void video_advanced_setup_toggled ()
1465         {
1466                 bool const x = _video_advanced_setup_button.get_active ();
1467                 _rc_config->set_video_advanced_setup(x);
1468         }
1469
1470         void parameter_changed (string const & p)
1471         {
1472                 if (p == "video-server-url") {
1473                         _video_server_url_entry.set_text (_rc_config->get_video_server_url());
1474                 } else if (p == "video-server-docroot") {
1475                         _video_server_docroot_entry.set_text (_rc_config->get_video_server_docroot());
1476                 } else if (p == "show-video-export-info") {
1477                         bool const x = _rc_config->get_show_video_export_info();
1478                         _show_video_export_info_button.set_active (x);
1479                 } else if (p == "show-video-server-dialog") {
1480                         bool const x = _rc_config->get_show_video_server_dialog();
1481                         _show_video_server_dialog_button.set_active (x);
1482                 } else if (p == "video-advanced-setup") {
1483                         bool const x = _rc_config->get_video_advanced_setup();
1484                         _video_advanced_setup_button.set_active(x);
1485                         _video_server_docroot_entry.set_sensitive(x);
1486                         _video_server_url_entry.set_sensitive(x);
1487                 }
1488         }
1489
1490         void set_state_from_config ()
1491         {
1492                 parameter_changed ("video-server-url");
1493                 parameter_changed ("video-server-docroot");
1494                 parameter_changed ("video-monitor-setup-dialog");
1495                 parameter_changed ("show-video-export-info");
1496                 parameter_changed ("show-video-server-dialog");
1497                 parameter_changed ("video-advanced-setup");
1498         }
1499
1500 private:
1501         RCConfiguration* _rc_config;
1502         Entry _video_server_url_entry;
1503         Entry _video_server_docroot_entry;
1504         CheckButton _show_video_export_info_button;
1505         CheckButton _show_video_server_dialog_button;
1506         CheckButton _video_advanced_setup_button;
1507 };
1508
1509 class PluginOptions : public OptionEditorBox
1510 {
1511 public:
1512         PluginOptions (RCConfiguration* c, UIConfiguration* uic)
1513                 : _rc_config (c)
1514                 , _ui_config (uic)
1515                 , _display_plugin_scan_progress (_("Always Display Plugin Scan Progress"))
1516                 , _discover_vst_on_start (_("Scan for [new] VST Plugins on Application Start"))
1517                 , _discover_au_on_start (_("Scan for AudioUnit Plugins on Application Start"))
1518                 , _verbose_plugin_scan (_("Verbose Plugin Scan"))
1519                 , _timeout_adjustment (0, 0, 3000, 50, 50)
1520                 , _timeout_slider (_timeout_adjustment)
1521         {
1522                 Label *l;
1523                 std::stringstream ss;
1524                 Table* t = manage (new Table (2, 6));
1525                 t->set_spacings (4);
1526                 Button* b;
1527                 int n = 0;
1528
1529                 ss << "<b>" << _("General") << "</b>";
1530                 l = manage (left_aligned_label (ss.str()));
1531                 l->set_use_markup (true);
1532                 t->attach (*manage (new Label ("")), 0, 3, n, n+1, FILL | EXPAND); ++n;
1533                 t->attach (*l, 0, 2, n, n+1, FILL | EXPAND); ++n;
1534
1535                 b = manage (new Button (_("Scan for Plugins")));
1536                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::refresh_clicked));
1537                 t->attach (*b, 0, 2, n, n+1, FILL); ++n;
1538
1539                 t->attach (_display_plugin_scan_progress, 0, 2, n, n+1); ++n;
1540                 _display_plugin_scan_progress.signal_toggled().connect (sigc::mem_fun (*this, &PluginOptions::display_plugin_scan_progress_toggled));
1541                 Gtkmm2ext::UI::instance()->set_tip (_display_plugin_scan_progress,
1542                                             _("<b>When enabled</b> a popup window showing plugin scan progress is displayed for indexing (cache load) and discovery (detect new plugins)"));
1543
1544 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
1545                 _timeout_slider.set_digits (0);
1546                 _timeout_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &PluginOptions::timeout_changed));
1547
1548                 Gtkmm2ext::UI::instance()->set_tip(_timeout_slider,
1549                          _("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."));
1550
1551                 l = manage (left_aligned_label (_("Scan Time Out [deciseconds]")));;
1552                 HBox* h = manage (new HBox);
1553                 h->set_spacing (4);
1554                 h->pack_start (*l, false, false);
1555                 h->pack_start (_timeout_slider, true, true);
1556                 t->attach (*h, 0, 2, n, n+1); ++n;
1557
1558                 ss.str("");
1559                 ss << "<b>" << _("VST") << "</b>";
1560                 l = manage (left_aligned_label (ss.str()));
1561                 l->set_use_markup (true);
1562                 t->attach (*manage (new Label ("")), 0, 3, n, n+1, FILL | EXPAND); ++n;
1563                 t->attach (*l, 0, 2, n, n+1, FILL | EXPAND); ++n;
1564
1565                 b = manage (new Button (_("Clear VST Cache")));
1566                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::clear_vst_cache_clicked));
1567                 t->attach (*b, 0, 1, n, n+1, FILL);
1568
1569                 b = manage (new Button (_("Clear VST Blacklist")));
1570                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::clear_vst_blacklist_clicked));
1571                 t->attach (*b, 1, 2, n, n+1, FILL);
1572                 ++n;
1573
1574                 t->attach (_discover_vst_on_start, 0, 2, n, n+1); ++n;
1575                 _discover_vst_on_start.signal_toggled().connect (sigc::mem_fun (*this, &PluginOptions::discover_vst_on_start_toggled));
1576                 Gtkmm2ext::UI::instance()->set_tip (_discover_vst_on_start,
1577                                             _("<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"));
1578
1579 #ifdef LXVST_SUPPORT
1580                 t->attach (*manage (left_aligned_label (_("Linux VST Path:"))), 0, 1, n, n+1);
1581                 b = manage (new Button (_("Edit")));
1582                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::edit_lxvst_path_clicked));
1583                 t->attach (*b, 1, 2, n, n+1, FILL); ++n;
1584 #endif
1585
1586 #ifdef WINDOWS_VST_SUPPORT
1587                 t->attach (*manage (left_aligned_label (_("Windows VST Path:"))), 0, 1, n, n+1);
1588                 b = manage (new Button (_("Edit")));
1589                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::edit_vst_path_clicked));
1590                 t->attach (*b, 1, 2, n, n+1, FILL); ++n;
1591
1592                 // currently verbose logging is only implemented for Windows VST.
1593                 t->attach (_verbose_plugin_scan, 0, 2, n, n+1); ++n;
1594                 _verbose_plugin_scan.signal_toggled().connect (sigc::mem_fun (*this, &PluginOptions::verbose_plugin_scan_toggled));
1595                 Gtkmm2ext::UI::instance()->set_tip (_verbose_plugin_scan,
1596                                             _("<b>When enabled</b> additional information for every plugin is added to the Log Window."));
1597 #endif
1598 #endif // any VST
1599
1600 #ifdef AUDIOUNIT_SUPPORT
1601                 ss.str("");
1602                 ss << "<b>" << _("Audio Unit") << "</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                 t->attach (_discover_au_on_start, 0, 2, n, n+1); ++n;
1609                 _discover_au_on_start.signal_toggled().connect (sigc::mem_fun (*this, &PluginOptions::discover_au_on_start_toggled));
1610                 Gtkmm2ext::UI::instance()->set_tip (_discover_au_on_start,
1611                                             _("<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."));
1612
1613                 ++n;
1614                 b = manage (new Button (_("Clear AU Cache")));
1615                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::clear_au_cache_clicked));
1616                 t->attach (*b, 0, 1, n, n+1, FILL);
1617
1618                 b = manage (new Button (_("Clear AU Blacklist")));
1619                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::clear_au_blacklist_clicked));
1620                 t->attach (*b, 1, 2, n, n+1, FILL);
1621                 ++n;
1622 #endif
1623
1624                 _box->pack_start (*t,true,true);
1625         }
1626
1627         void parameter_changed (string const & p) {
1628                 if (p == "show-plugin-scan-window") {
1629                         bool const x = _ui_config->get_show_plugin_scan_window();
1630                         _display_plugin_scan_progress.set_active (x);
1631                 }
1632                 else if (p == "discover-vst-on-start") {
1633                         bool const x = _rc_config->get_discover_vst_on_start();
1634                         _discover_vst_on_start.set_active (x);
1635                 }
1636                 else if (p == "vst-scan-timeout") {
1637                         int const x = _rc_config->get_vst_scan_timeout();
1638                         _timeout_adjustment.set_value (x);
1639                 }
1640                 else if (p == "discover-audio-units") {
1641                         bool const x = _rc_config->get_discover_audio_units();
1642                         _discover_au_on_start.set_active (x);
1643                 }
1644                 else if (p == "verbose-plugin-scan") {
1645                         bool const x = _rc_config->get_verbose_plugin_scan();
1646                         _verbose_plugin_scan.set_active (x);
1647                 }
1648         }
1649
1650         void set_state_from_config () {
1651                 parameter_changed ("show-plugin-scan-window");
1652                 parameter_changed ("discover-vst-on-start");
1653                 parameter_changed ("vst-scan-timeout");
1654                 parameter_changed ("discover-audio-units");
1655                 parameter_changed ("verbose-plugin-scan");
1656         }
1657
1658 private:
1659         RCConfiguration* _rc_config;
1660         UIConfiguration* _ui_config;
1661         CheckButton _display_plugin_scan_progress;
1662         CheckButton _discover_vst_on_start;
1663         CheckButton _discover_au_on_start;
1664         CheckButton _verbose_plugin_scan;
1665         Adjustment _timeout_adjustment;
1666         HScale _timeout_slider;
1667
1668         void display_plugin_scan_progress_toggled () {
1669                 bool const x = _display_plugin_scan_progress.get_active();
1670                 _ui_config->set_show_plugin_scan_window(x);
1671         }
1672
1673         void discover_vst_on_start_toggled () {
1674                 bool const x = _discover_vst_on_start.get_active();
1675                 _rc_config->set_discover_vst_on_start(x);
1676         }
1677
1678         void discover_au_on_start_toggled () {
1679                 bool const x = _discover_au_on_start.get_active();
1680                 _rc_config->set_discover_audio_units(x);
1681         }
1682
1683         void verbose_plugin_scan_toggled () {
1684                 bool const x = _verbose_plugin_scan.get_active();
1685                 _rc_config->set_verbose_plugin_scan(x);
1686         }
1687
1688         void timeout_changed () {
1689                 int x = floor(_timeout_adjustment.get_value());
1690                 _rc_config->set_vst_scan_timeout(x);
1691         }
1692
1693         void clear_vst_cache_clicked () {
1694                 PluginManager::instance().clear_vst_cache();
1695         }
1696
1697         void clear_vst_blacklist_clicked () {
1698                 PluginManager::instance().clear_vst_blacklist();
1699         }
1700
1701         void clear_au_cache_clicked () {
1702                 PluginManager::instance().clear_au_cache();
1703         }
1704
1705         void clear_au_blacklist_clicked () {
1706                 PluginManager::instance().clear_au_blacklist();
1707         }
1708
1709
1710         void edit_vst_path_clicked () {
1711                 Gtkmm2ext::PathsDialog *pd = new Gtkmm2ext::PathsDialog (
1712                                 _("Set Windows VST Search Path"),
1713                                 _rc_config->get_plugin_path_vst(),
1714                                 PluginManager::instance().get_default_windows_vst_path()
1715                         );
1716                 ResponseType r = (ResponseType) pd->run ();
1717                 pd->hide();
1718                 if (r == RESPONSE_ACCEPT) {
1719                         _rc_config->set_plugin_path_vst(pd->get_serialized_paths());
1720                 }
1721                 delete pd;
1722         }
1723
1724         // todo consolidate with edit_vst_path_clicked..
1725         void edit_lxvst_path_clicked () {
1726                 Gtkmm2ext::PathsDialog *pd = new Gtkmm2ext::PathsDialog (
1727                                 _("Set Linux VST Search Path"),
1728                                 _rc_config->get_plugin_path_lxvst(),
1729                                 PluginManager::instance().get_default_lxvst_path()
1730                                 );
1731                 ResponseType r = (ResponseType) pd->run ();
1732                 pd->hide();
1733                 if (r == RESPONSE_ACCEPT) {
1734                         _rc_config->set_plugin_path_lxvst(pd->get_serialized_paths());
1735                 }
1736                 delete pd;
1737         }
1738
1739         void refresh_clicked () {
1740                 PluginManager::instance().refresh();
1741         }
1742 };
1743
1744
1745 /** A class which allows control of visibility of some editor components usign
1746  *  a VisibilityGroup.  The caller should pass in a `dummy' VisibilityGroup
1747  *  which has the correct members, but with null widget pointers.  This
1748  *  class allows the user to set visibility of the members, the details
1749  *  of which are stored in a configuration variable which can be watched
1750  *  by parts of the editor that actually contain the widgets whose visibility
1751  *  is being controlled.
1752  */
1753
1754 class VisibilityOption : public Option
1755 {
1756 public:
1757         /** @param name User-visible name for this group.
1758          *  @param g `Dummy' VisibilityGroup (as described above).
1759          *  @param get Method to get the value of the appropriate configuration variable.
1760          *  @param set Method to set the value of the appropriate configuration variable.
1761          */
1762         VisibilityOption (string name, VisibilityGroup* g, sigc::slot<string> get, sigc::slot<bool, string> set)
1763                 : Option (g->get_state_name(), name)
1764                 , _heading (name)
1765                 , _visibility_group (g)
1766                 , _get (get)
1767                 , _set (set)
1768         {
1769                 /* Watch for changes made by the user to our members */
1770                 _visibility_group->VisibilityChanged.connect_same_thread (
1771                         _visibility_group_connection, sigc::bind (&VisibilityOption::changed, this)
1772                         );
1773         }
1774
1775         void set_state_from_config ()
1776         {
1777                 /* Set our state from the current configuration */
1778                 _visibility_group->set_state (_get ());
1779         }
1780
1781         void add_to_page (OptionEditorPage* p)
1782         {
1783                 _heading.add_to_page (p);
1784                 add_widget_to_page (p, _visibility_group->list_view ());
1785         }
1786
1787         Gtk::Widget& tip_widget() { return *_visibility_group->list_view (); }
1788
1789 private:
1790         void changed ()
1791         {
1792                 /* The user has changed something, so reflect this change
1793                    in the RCConfiguration.
1794                 */
1795                 _set (_visibility_group->get_state_value ());
1796         }
1797         
1798         OptionEditorHeading _heading;
1799         VisibilityGroup* _visibility_group;
1800         sigc::slot<std::string> _get;
1801         sigc::slot<bool, std::string> _set;
1802         PBD::ScopedConnection _visibility_group_connection;
1803 };
1804
1805
1806
1807 RCOptionEditor::RCOptionEditor ()
1808         : OptionEditor (Config, string_compose (_("%1 Preferences"), PROGRAM_NAME))
1809         , _rc_config (Config)
1810         , _ui_config (ARDOUR_UI::config())
1811         , _mixer_strip_visibility ("mixer-element-visibility")
1812 {
1813         /* MISC */
1814
1815         uint32_t hwcpus = hardware_concurrency ();
1816         BoolOption* bo;
1817         BoolComboOption* bco;
1818
1819         if (hwcpus > 1) {
1820                 add_option (_("Misc"), new OptionEditorHeading (_("DSP CPU Utilization")));
1821
1822                 ComboOption<int32_t>* procs = new ComboOption<int32_t> (
1823                         "processor-usage",
1824                         _("Signal processing uses"),
1825                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_processor_usage),
1826                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_processor_usage)
1827                         );
1828
1829                 procs->add (-1, _("all but one processor"));
1830                 procs->add (0, _("all available processors"));
1831
1832                 for (uint32_t i = 1; i <= hwcpus; ++i) {
1833                         procs->add (i, string_compose (_("%1 processors"), i));
1834                 }
1835
1836                 procs->set_note (string_compose (_("This setting will only take effect when %1 is restarted."), PROGRAM_NAME));
1837
1838                 add_option (_("Misc"), procs);
1839         }
1840
1841         add_option (_("Misc"), new OptionEditorHeading (S_("Options|Undo")));
1842
1843         add_option (_("Misc"), new UndoOptions (_rc_config));
1844
1845         add_option (_("Misc"),
1846              new BoolOption (
1847                      "verify-remove-last-capture",
1848                      _("Verify removal of last capture"),
1849                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_verify_remove_last_capture),
1850                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_verify_remove_last_capture)
1851                      ));
1852
1853         add_option (_("Misc"),
1854              new BoolOption (
1855                      "periodic-safety-backups",
1856                      _("Make periodic backups of the session file"),
1857                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_periodic_safety_backups),
1858                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_periodic_safety_backups)
1859                      ));
1860
1861         add_option (_("Misc"), new OptionEditorHeading (_("Session Management")));
1862
1863         add_option (_("Misc"),
1864              new BoolOption (
1865                      "only-copy-imported-files",
1866                      _("Always copy imported files"),
1867                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_only_copy_imported_files),
1868                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_only_copy_imported_files)
1869                      ));
1870
1871         add_option (_("Misc"), new DirectoryOption (
1872                             X_("default-session-parent-dir"),
1873                             _("Default folder for new sessions:"),
1874                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_default_session_parent_dir),
1875                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_default_session_parent_dir)
1876                             ));
1877
1878         add_option (_("Misc"),
1879              new SpinOption<uint32_t> (
1880                      "max-recent-sessions",
1881                      _("Maximum number of recent sessions"),
1882                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_max_recent_sessions),
1883                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_max_recent_sessions),
1884                      0, 1000, 1, 20
1885                      ));
1886
1887         add_option (_("Misc"), new OptionEditorHeading (_("Click")));
1888
1889         add_option (_("Misc"), new ClickOptions (_rc_config, this));
1890
1891         add_option (_("Misc"),
1892              new FaderOption (
1893                      "click-gain",
1894                      _("Click gain level"),
1895                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_click_gain),
1896                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_click_gain)
1897                      ));
1898
1899         add_option (_("Misc"), new OptionEditorHeading (_("Automation")));
1900
1901         add_option (_("Misc"),
1902              new SpinOption<double> (
1903                      "automation-thinning-factor",
1904                      _("Thinning factor (larger value => less data)"),
1905                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_thinning_factor),
1906                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_thinning_factor),
1907                      0, 1000, 1, 20
1908                      ));
1909
1910         add_option (_("Misc"),
1911              new SpinOption<double> (
1912                      "automation-interval-msecs",
1913                      _("Automation sampling interval (milliseconds)"),
1914                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_interval_msecs),
1915                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_interval_msecs),
1916                      1, 1000, 1, 20
1917                      ));
1918
1919         /* TRANSPORT */
1920
1921         add_option (_("Transport"), new OptionEditorHeading (S_("Playhead Behaviour")));
1922         add_option (_("Transport"), new AutoReturnTargetOptions (_rc_config, this));
1923         add_option (_("Transport"), new OptionEditorHeading (S_("Transport Options")));
1924
1925         BoolOption* tsf;
1926
1927         tsf = new BoolOption (
1928                      "latched-record-enable",
1929                      _("Keep record-enable engaged on stop"),
1930                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_latched_record_enable),
1931                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_latched_record_enable)
1932                      );
1933         // Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _(""));
1934         add_option (_("Transport"), tsf);
1935
1936         tsf = new BoolOption (
1937                      "loop-is-mode",
1938                      _("Play loop is a transport mode"),
1939                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_loop_is_mode),
1940                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_loop_is_mode)
1941                      );
1942         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), 
1943                                             (_("<b>When enabled</b> the loop button does not start playback but forces playback to always play the loop\n\n"
1944                                                "<b>When disabled</b> the loop button starts playing the loop, but stop then cancels loop playback")));
1945         add_option (_("Transport"), tsf);
1946         
1947         tsf = new BoolOption (
1948                      "stop-recording-on-xrun",
1949                      _("Stop recording when an xrun occurs"),
1950                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_recording_on_xrun),
1951                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_recording_on_xrun)
1952                      );
1953         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), 
1954                                             string_compose (_("<b>When enabled</b> %1 will stop recording if an over- or underrun is detected by the audio engine"),
1955                                                             PROGRAM_NAME));
1956         add_option (_("Transport"), tsf);
1957
1958         tsf = new BoolOption (
1959                      "create-xrun-marker",
1960                      _("Create markers where xruns occur"),
1961                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_create_xrun_marker),
1962                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_create_xrun_marker)
1963                      );
1964         // Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _(""));
1965         add_option (_("Transport"), tsf);
1966
1967         tsf = new BoolOption (
1968                      "stop-at-session-end",
1969                      _("Stop at the end of the session"),
1970                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_at_session_end),
1971                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_at_session_end)
1972                      );
1973         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), 
1974                                             string_compose (_("<b>When enabled</b> if %1 is <b>not recording</b>, it will stop the transport "
1975                                                               "when it reaches the current session end marker\n\n"
1976                                                               "<b>When disabled</b> %1 will continue to roll past the session end marker at all times"),
1977                                                             PROGRAM_NAME));
1978         add_option (_("Transport"), tsf);
1979
1980         tsf = new BoolOption (
1981                      "seamless-loop",
1982                      _("Do seamless looping (not possible when slaved to MTC, LTC etc)"),
1983                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_seamless_loop),
1984                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_seamless_loop)
1985                      );
1986         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), 
1987                                             string_compose (_("<b>When enabled</b> this will loop by reading ahead and wrapping around at the loop point, "
1988                                                               "preventing any need to do a transport locate at the end of the loop\n\n"
1989                                                               "<b>When disabled</b> looping is done by locating back to the start of the loop when %1 reaches the end "
1990                                                               "which will often cause a small click or delay"), PROGRAM_NAME));
1991         add_option (_("Transport"), tsf);
1992
1993         tsf = new BoolOption (
1994                      "disable-disarm-during-roll",
1995                      _("Disable per-track record disarm while rolling"),
1996                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_disable_disarm_during_roll),
1997                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_disable_disarm_during_roll)
1998                      );
1999         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"));
2000         add_option (_("Transport"), tsf);
2001
2002         tsf = new BoolOption (
2003                      "quieten_at_speed",
2004                      _("12dB gain reduction during fast-forward and fast-rewind"),
2005                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_quieten_at_speed),
2006                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_quieten_at_speed)
2007                      );
2008         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _("This will reduce the unpleasant increase in perceived volume "
2009                                                    "that occurs when fast-forwarding or rewinding through some kinds of audio"));
2010         add_option (_("Transport"), tsf);
2011
2012         add_option (_("Transport"), new OptionEditorHeading (S_("Sync/Slave")));
2013
2014         _sync_source = new ComboOption<SyncSource> (
2015                 "sync-source",
2016                 _("External timecode source"),
2017                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_sync_source),
2018                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_sync_source)
2019                 );
2020
2021         add_option (_("Transport"), _sync_source);
2022
2023         _sync_framerate = new BoolOption (
2024                      "timecode-sync-frame-rate",
2025                      _("Match session video frame rate to external timecode"),
2026                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_sync_frame_rate),
2027                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_sync_frame_rate)
2028                      );
2029         Gtkmm2ext::UI::instance()->set_tip 
2030                 (_sync_framerate->tip_widget(),
2031                  string_compose (_("This option controls the value of the video frame rate <i>while chasing</i> an external timecode source.\n\n"
2032                                    "<b>When enabled</b> the session video frame rate will be changed to match that of the selected external timecode source.\n\n"
2033                                    "<b>When disabled</b> the session video frame rate will not be changed to match that of the selected external timecode source."
2034                                    "Instead the frame rate indication in the main clock will flash red and %1 will convert between the external "
2035                                    "timecode standard and the session standard."), PROGRAM_NAME));
2036
2037         add_option (_("Transport"), _sync_framerate);
2038
2039         _sync_genlock = new BoolOption (
2040                 "timecode-source-is-synced",
2041                 _("Sync-lock timecode to clock (disable drift compensation)"),
2042                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_is_synced),
2043                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_is_synced)
2044                 );
2045         Gtkmm2ext::UI::instance()->set_tip 
2046                 (_sync_genlock->tip_widget(),
2047                  string_compose (_("<b>When enabled</b> %1 will never varispeed when slaved to external timecode. "
2048                                    "Sync Lock indicates that the selected external timecode source shares clock-sync "
2049                                    "(Black &amp; Burst, Wordclock, etc) with the audio interface. "
2050                                    "This option disables drift compensation. The transport speed is fixed at 1.0. "
2051                                    "Vari-speed LTC will be ignored and cause drift."
2052                                    "\n\n"
2053                                    "<b>When disabled</b> %1 will compensate for potential drift, regardless if the "
2054                                    "timecode sources shares clock sync."
2055                                   ), PROGRAM_NAME));
2056
2057
2058         add_option (_("Transport"), _sync_genlock);
2059
2060         _sync_source_2997 = new BoolOption (
2061                 "timecode-source-2997",
2062                 _("Lock to 29.9700 fps instead of 30000/1001"),
2063                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_2997),
2064                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_2997)
2065                 );
2066         Gtkmm2ext::UI::instance()->set_tip
2067                 (_sync_source_2997->tip_widget(),
2068                  _("<b>When enabled</b> the external timecode source is assumed to use 29.97 fps instead of 30000/1001.\n"
2069                          "SMPTE 12M-1999 specifies 29.97df as 30000/1001. The spec further mentions that "
2070                          "drop-frame timecode has an accumulated error of -86ms over a 24-hour period.\n"
2071                          "Drop-frame timecode would compensate exactly for a NTSC color frame rate of 30 * 0.9990 (ie 29.970000). "
2072                          "That is not the actual rate. However, some vendors use that rate - despite it being against the specs - "
2073                          "because the variant of using exactly 29.97 fps has zero timecode drift.\n"
2074                          ));
2075
2076         add_option (_("Transport"), _sync_source_2997);
2077
2078         add_option (_("Transport"), new OptionEditorHeading (S_("LTC Reader")));
2079
2080         _ltc_port = new ComboStringOption (
2081                 "ltc-source-port",
2082                 _("LTC incoming port"),
2083                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_source_port),
2084                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_source_port)
2085                 );
2086
2087         vector<string> physical_inputs;
2088         physical_inputs.push_back (_("None"));
2089         AudioEngine::instance()->get_physical_inputs (DataType::AUDIO, physical_inputs);
2090         _ltc_port->set_popdown_strings (physical_inputs);
2091
2092         populate_sync_options ();
2093
2094         add_option (_("Transport"), _ltc_port);
2095
2096         // TODO; rather disable this button than not compile it..
2097         add_option (_("Transport"), new OptionEditorHeading (S_("LTC Generator")));
2098
2099         add_option (_("Transport"),
2100                     new BoolOption (
2101                             "send-ltc",
2102                             _("Enable LTC generator"),
2103                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_ltc),
2104                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_ltc)
2105                             ));
2106
2107         _ltc_send_continuously = new BoolOption (
2108                             "ltc-send-continuously",
2109                             _("Send LTC while stopped"),
2110                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_send_continuously),
2111                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_send_continuously)
2112                             );
2113         Gtkmm2ext::UI::instance()->set_tip
2114                 (_ltc_send_continuously->tip_widget(),
2115                  string_compose (_("<b>When enabled</b> %1 will continue to send LTC information even when the transport (playhead) is not moving"), PROGRAM_NAME));
2116         add_option (_("Transport"), _ltc_send_continuously);
2117
2118         _ltc_volume_adjustment = new Gtk::Adjustment(-18, -50, 0, .5, 5);
2119         _ltc_volume_adjustment->set_value (20 * log10(_rc_config->get_ltc_output_volume()));
2120         _ltc_volume_adjustment->signal_value_changed().connect (sigc::mem_fun (*this, &RCOptionEditor::ltc_generator_volume_changed));
2121         _ltc_volume_slider = new HSliderOption("ltcvol", _("LTC generator level"), *_ltc_volume_adjustment);
2122
2123         Gtkmm2ext::UI::instance()->set_tip
2124                 (_ltc_volume_slider->tip_widget(),
2125                  _("Specify the Peak Volume of the generated LTC signal in dbFS. A good value is  0dBu ^= -18dbFS in an EBU calibrated system"));
2126
2127         add_option (_("Transport"), _ltc_volume_slider);
2128         parameter_changed ("send-ltc");
2129
2130         parameter_changed ("sync-source");
2131
2132         /* EDITOR */
2133
2134         add_option (S_("Editor"),
2135              new BoolOption (
2136                      "draggable-playhead",
2137                      _("Allow dragging of playhead"),
2138                      sigc::mem_fun (*ARDOUR_UI::config(), &UIConfiguration::get_draggable_playhead),
2139                      sigc::mem_fun (*ARDOUR_UI::config(), &UIConfiguration::set_draggable_playhead)
2140                      ));
2141
2142         add_option (_("Editor"),
2143              new BoolOption (
2144                      "automation-follows-regions",
2145                      _("Move relevant automation when audio regions are moved"),
2146                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_follows_regions),
2147                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_follows_regions)
2148                      ));
2149
2150         add_option (_("Editor"),
2151              new BoolOption (
2152                      "show-track-meters",
2153                      _("Show meters on tracks in the editor"),
2154                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_show_track_meters),
2155                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_show_track_meters)
2156                      ));
2157
2158         add_option (_("Editor"),
2159              new BoolOption (
2160                      "show-editor-meter",
2161                      _("Display master-meter in the toolbar"),
2162                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_show_editor_meter),
2163                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_show_editor_meter)
2164                      ));
2165
2166         ComboOption<FadeShape>* fadeshape = new ComboOption<FadeShape> (
2167                         "default-fade-shape",
2168                         _("Default fade shape"),
2169                         sigc::mem_fun (*_rc_config,
2170                                 &RCConfiguration::get_default_fade_shape),
2171                         sigc::mem_fun (*_rc_config,
2172                                 &RCConfiguration::set_default_fade_shape)
2173                         );
2174
2175         fadeshape->add (FadeLinear,
2176                         _("Linear (for highly correlated material)"));
2177         fadeshape->add (FadeConstantPower, _("Constant power"));
2178         fadeshape->add (FadeSymmetric, _("Symmetric"));
2179         fadeshape->add (FadeSlow, _("Slow"));
2180         fadeshape->add (FadeFast, _("Fast"));
2181
2182         add_option (_("Editor"), fadeshape);
2183
2184
2185         bco = new BoolComboOption (
2186                      "use-overlap-equivalency",
2187                      _("Regions in active edit groups are edited together"),
2188                      _("whenever they overlap in time"),
2189                      _("only if they have identical length, position and origin"),
2190                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_use_overlap_equivalency),
2191                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_use_overlap_equivalency)
2192                      );
2193
2194         add_option (_("Editor"), bco);
2195
2196         ComboOption<LayerModel>* lm = new ComboOption<LayerModel> (
2197                 "layer-model",
2198                 _("Layering model"),
2199                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_layer_model),
2200                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_layer_model)
2201                 );
2202
2203         lm->add (LaterHigher, _("later is higher"));
2204         lm->add (Manual, _("manual layering"));
2205         add_option (_("Editor"), lm);
2206
2207         add_option (_("Editor"),
2208              new BoolOption (
2209                      "rubberbanding-snaps-to-grid",
2210                      _("Make rubberband selection rectangle snap to the grid"),
2211                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_rubberbanding_snaps_to_grid),
2212                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_rubberbanding_snaps_to_grid)
2213                      ));
2214
2215         add_option (_("Editor"),
2216              new BoolOption (
2217                      "show-waveforms",
2218                      _("Show waveforms in regions"),
2219                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_show_waveforms),
2220                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_show_waveforms)
2221                      ));
2222
2223         add_option (_("Editor"),
2224              new BoolComboOption (
2225                      "show-region-gain-envelopes",
2226                      _("Show gain envelopes in audio regions"),
2227                      _("in all modes"),
2228                      _("only in Draw and Internal Edit modes"),
2229                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_show_region_gain),
2230                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_show_region_gain)
2231                      ));
2232
2233         ComboOption<WaveformScale>* wfs = new ComboOption<WaveformScale> (
2234                 "waveform-scale",
2235                 _("Waveform scale"),
2236                 sigc::mem_fun (*_ui_config, &UIConfiguration::get_waveform_scale),
2237                 sigc::mem_fun (*_ui_config, &UIConfiguration::set_waveform_scale)
2238                 );
2239
2240         wfs->add (Linear, _("linear"));
2241         wfs->add (Logarithmic, _("logarithmic"));
2242
2243         add_option (_("Editor"), wfs);
2244
2245         ComboOption<WaveformShape>* wfsh = new ComboOption<WaveformShape> (
2246                 "waveform-shape",
2247                 _("Waveform shape"),
2248                 sigc::mem_fun (*_ui_config, &UIConfiguration::get_waveform_shape),
2249                 sigc::mem_fun (*_ui_config, &UIConfiguration::set_waveform_shape)
2250                 );
2251
2252         wfsh->add (Traditional, _("traditional"));
2253         wfsh->add (Rectified, _("rectified"));
2254
2255         add_option (_("Editor"), wfsh);
2256
2257         add_option (_("Editor"), new ClipLevelOptions (_ui_config));
2258
2259         add_option (_("Editor"),
2260              new BoolOption (
2261                      "show-waveforms-while-recording",
2262                      _("Show waveforms for audio while it is being recorded"),
2263                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_show_waveforms_while_recording),
2264                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_show_waveforms_while_recording)
2265                      ));
2266
2267         add_option (_("Editor"),
2268                     new BoolOption (
2269                             "show-zoom-tools",
2270                             _("Show zoom toolbar"),
2271                             sigc::mem_fun (*_ui_config, &UIConfiguration::get_show_zoom_tools),
2272                             sigc::mem_fun (*_ui_config, &UIConfiguration::set_show_zoom_tools)
2273                             ));
2274
2275         add_option (_("Editor"),
2276                     new BoolOption (
2277                             "update-editor-during-summary-drag",
2278                             _("Update editor window during drags of the summary"),
2279                             sigc::mem_fun (*_ui_config, &UIConfiguration::get_update_editor_during_summary_drag),
2280                             sigc::mem_fun (*_ui_config, &UIConfiguration::set_update_editor_during_summary_drag)
2281                             ));
2282
2283         bo = new BoolOption (
2284                      "name-new-markers",
2285                      _("Name new markers"),
2286                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_name_new_markers),
2287                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_name_new_markers)
2288                 );
2289         
2290         add_option (_("Editor"), bo);
2291         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."
2292                                                                 "\n\nYou can always rename markers by right-clicking on them"));
2293
2294         add_option (_("Editor"),
2295             new BoolOption (
2296                     "autoscroll-editor",
2297                     _("Auto-scroll editor window when dragging near its edges"),
2298                     sigc::mem_fun (*_ui_config, &UIConfiguration::get_autoscroll_editor),
2299                     sigc::mem_fun (*_ui_config, &UIConfiguration::set_autoscroll_editor)
2300                     ));
2301
2302         ComboOption<RegionSelectionAfterSplit> *rsas = new ComboOption<RegionSelectionAfterSplit> (
2303                     "region-selection-after-split",
2304                     _("After splitting selected regions, select"),
2305                     sigc::mem_fun (*_rc_config, &RCConfiguration::get_region_selection_after_split),
2306                     sigc::mem_fun (*_rc_config, &RCConfiguration::set_region_selection_after_split));
2307
2308         // TODO: decide which of these modes are really useful
2309         rsas->add(None, _("no regions"));
2310         // rsas->add(NewlyCreatedLeft, _("newly-created regions before the split"));
2311         // rsas->add(NewlyCreatedRight, _("newly-created regions after the split"));
2312         rsas->add(NewlyCreatedBoth, _("newly-created regions"));
2313         // rsas->add(Existing, _("unmodified regions in the existing selection"));
2314         // rsas->add(ExistingNewlyCreatedLeft, _("existing selection and newly-created regions before the split"));
2315         // rsas->add(ExistingNewlyCreatedRight, _("existing selection and newly-created regions after the split"));
2316         rsas->add(ExistingNewlyCreatedBoth, _("existing selection and newly-created regions"));
2317
2318         add_option (_("Editor"), rsas);
2319
2320
2321         /* AUDIO */
2322
2323         add_option (_("Audio"), new OptionEditorHeading (_("Buffering")));
2324
2325         add_option (_("Audio"), new BufferingOptions (_rc_config));
2326
2327         add_option (_("Audio"), new OptionEditorHeading (_("Monitoring")));
2328
2329         ComboOption<MonitorModel>* mm = new ComboOption<MonitorModel> (
2330                 "monitoring-model",
2331                 _("Record monitoring handled by"),
2332                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_monitoring_model),
2333                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_monitoring_model)
2334                 );
2335
2336         if (AudioEngine::instance()->port_engine().can_monitor_input()) {
2337                 mm->add (HardwareMonitoring, _("via Audio Driver"));
2338         }
2339
2340         string prog (PROGRAM_NAME);
2341         boost::algorithm::to_lower (prog);
2342         mm->add (SoftwareMonitoring, string_compose (_("%1"), prog));
2343         mm->add (ExternalMonitoring, _("audio hardware"));
2344
2345         add_option (_("Audio"), mm);
2346
2347         add_option (_("Audio"),
2348              new BoolOption (
2349                      "tape-machine-mode",
2350                      _("Tape machine mode"),
2351                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_tape_machine_mode),
2352                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_tape_machine_mode)
2353                      ));
2354
2355         add_option (_("Audio"), new OptionEditorHeading (_("Connection of tracks and busses")));
2356
2357         add_option (_("Audio"),
2358                     new BoolOption (
2359                             "auto-connect-standard-busses",
2360                             _("Auto-connect master/monitor busses"),
2361                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_connect_standard_busses),
2362                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_connect_standard_busses)
2363                             ));
2364
2365         ComboOption<AutoConnectOption>* iac = new ComboOption<AutoConnectOption> (
2366                 "input-auto-connect",
2367                 _("Connect track inputs"),
2368                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_input_auto_connect),
2369                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_input_auto_connect)
2370                 );
2371
2372         iac->add (AutoConnectPhysical, _("automatically to physical inputs"));
2373         iac->add (ManualConnect, _("manually"));
2374
2375         add_option (_("Audio"), iac);
2376
2377         ComboOption<AutoConnectOption>* oac = new ComboOption<AutoConnectOption> (
2378                 "output-auto-connect",
2379                 _("Connect track and bus outputs"),
2380                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_output_auto_connect),
2381                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_output_auto_connect)
2382                 );
2383
2384         oac->add (AutoConnectPhysical, _("automatically to physical outputs"));
2385         oac->add (AutoConnectMaster, _("automatically to master bus"));
2386         oac->add (ManualConnect, _("manually"));
2387
2388         add_option (_("Audio"), oac);
2389
2390         add_option (_("Audio"), new OptionEditorHeading (_("Denormals")));
2391
2392         add_option (_("Audio"),
2393              new BoolOption (
2394                      "denormal-protection",
2395                      _("Use DC bias to protect against denormals"),
2396                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_protection),
2397                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_protection)
2398                      ));
2399
2400         ComboOption<DenormalModel>* dm = new ComboOption<DenormalModel> (
2401                 "denormal-model",
2402                 _("Processor handling"),
2403                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_model),
2404                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_model)
2405                 );
2406
2407         int dmsize = 1;
2408         dm->add (DenormalNone, _("no processor handling"));
2409
2410         FPU* fpu = FPU::instance();
2411
2412         if (fpu->has_flush_to_zero()) {
2413                 ++dmsize;
2414                 dm->add (DenormalFTZ, _("use FlushToZero"));
2415         } else if (_rc_config->get_denormal_model() == DenormalFTZ) {
2416                 _rc_config->set_denormal_model(DenormalNone);
2417         }
2418
2419         if (fpu->has_denormals_are_zero()) {
2420                 ++dmsize;
2421                 dm->add (DenormalDAZ, _("use DenormalsAreZero"));
2422         } else if (_rc_config->get_denormal_model() == DenormalDAZ) {
2423                 _rc_config->set_denormal_model(DenormalNone);
2424         }
2425
2426         if (fpu->has_flush_to_zero() && fpu->has_denormals_are_zero()) {
2427                 ++dmsize;
2428                 dm->add (DenormalFTZDAZ, _("use FlushToZero and DenormalsAreZero"));
2429         } else if (_rc_config->get_denormal_model() == DenormalFTZDAZ) {
2430                 _rc_config->set_denormal_model(DenormalNone);
2431         }
2432
2433         if (dmsize == 1) {
2434                 dm->set_sensitive(false);
2435         }
2436
2437         add_option (_("Audio"), dm);
2438
2439         add_option (_("Audio"), new OptionEditorHeading (_("Plugins")));
2440
2441         add_option (_("Audio"),
2442              new BoolOption (
2443                      "plugins-stop-with-transport",
2444                      _("Silence plugins when the transport is stopped"),
2445                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugins_stop_with_transport),
2446                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_plugins_stop_with_transport)
2447                      ));
2448
2449         add_option (_("Audio"),
2450              new BoolOption (
2451                      "new-plugins-active",
2452                      _("Make new plugins active"),
2453                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_new_plugins_active),
2454                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_new_plugins_active)
2455                      ));
2456
2457         add_option (_("Audio"), new OptionEditorHeading (_("Regions")));
2458
2459         add_option (_("Audio"),
2460              new BoolOption (
2461                      "auto-analyse-audio",
2462                      _("Enable automatic analysis of audio"),
2463                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_analyse_audio),
2464                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_analyse_audio)
2465                      ));
2466
2467         add_option (_("Audio"),
2468              new BoolOption (
2469                      "replicate-missing-region-channels",
2470                      _("Replicate missing region channels"),
2471                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_replicate_missing_region_channels),
2472                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_replicate_missing_region_channels)
2473                      ));
2474
2475         /* SOLO AND MUTE */
2476
2477         add_option (_("Solo / mute"), new OptionEditorHeading (_("Solo")));
2478
2479         add_option (_("Solo / mute"),
2480              new FaderOption (
2481                      "solo-mute-gain",
2482                      _("Solo-in-place mute cut (dB)"),
2483                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_gain),
2484                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_gain)
2485                      ));
2486
2487         _solo_control_is_listen_control = new BoolOption (
2488                 "solo-control-is-listen-control",
2489                 _("Solo controls are Listen controls"),
2490                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_control_is_listen_control),
2491                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_control_is_listen_control)
2492                 );
2493
2494         add_option (_("Solo / mute"), _solo_control_is_listen_control);
2495
2496         _listen_position = new ComboOption<ListenPosition> (
2497                 "listen-position",
2498                 _("Listen Position"),
2499                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_listen_position),
2500                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_listen_position)
2501                 );
2502
2503         _listen_position->add (AfterFaderListen, _("after-fader (AFL)"));
2504         _listen_position->add (PreFaderListen, _("pre-fader (PFL)"));
2505
2506         add_option (_("Solo / mute"), _listen_position);
2507
2508         ComboOption<PFLPosition>* pp = new ComboOption<PFLPosition> (
2509                 "pfl-position",
2510                 _("PFL signals come from"),
2511                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_pfl_position),
2512                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_pfl_position)
2513                 );
2514
2515         pp->add (PFLFromBeforeProcessors, _("before pre-fader processors"));
2516         pp->add (PFLFromAfterProcessors, _("pre-fader but after pre-fader processors"));
2517
2518         add_option (_("Solo / mute"), pp);
2519
2520         ComboOption<AFLPosition>* pa = new ComboOption<AFLPosition> (
2521                 "afl-position",
2522                 _("AFL signals come from"),
2523                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_afl_position),
2524                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_afl_position)
2525                 );
2526
2527         pa->add (AFLFromBeforeProcessors, _("immediately post-fader"));
2528         pa->add (AFLFromAfterProcessors, _("after post-fader processors (before pan)"));
2529
2530         add_option (_("Solo / mute"), pa);
2531
2532         parameter_changed ("use-monitor-bus");
2533
2534         add_option (_("Solo / mute"),
2535              new BoolOption (
2536                      "exclusive-solo",
2537                      _("Exclusive solo"),
2538                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_exclusive_solo),
2539                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_exclusive_solo)
2540                      ));
2541
2542         add_option (_("Solo / mute"),
2543              new BoolOption (
2544                      "show-solo-mutes",
2545                      _("Show solo muting"),
2546                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_show_solo_mutes),
2547                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_solo_mutes)
2548                      ));
2549
2550         add_option (_("Solo / mute"),
2551              new BoolOption (
2552                      "solo-mute-override",
2553                      _("Soloing overrides muting"),
2554                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_override),
2555                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_override)
2556                      ));
2557
2558         add_option (_("Solo / mute"), new OptionEditorHeading (_("Default track / bus muting options")));
2559
2560         add_option (_("Solo / mute"),
2561              new BoolOption (
2562                      "mute-affects-pre-fader",
2563                      _("Mute affects pre-fader sends"),
2564                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_pre_fader),
2565                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_pre_fader)
2566                      ));
2567
2568         add_option (_("Solo / mute"),
2569              new BoolOption (
2570                      "mute-affects-post-fader",
2571                      _("Mute affects post-fader sends"),
2572                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_post_fader),
2573                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_post_fader)
2574                      ));
2575
2576         add_option (_("Solo / mute"),
2577              new BoolOption (
2578                      "mute-affects-control-outs",
2579                      _("Mute affects control outputs"),
2580                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_control_outs),
2581                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_control_outs)
2582                      ));
2583
2584         add_option (_("Solo / mute"),
2585              new BoolOption (
2586                      "mute-affects-main-outs",
2587                      _("Mute affects main outputs"),
2588                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_main_outs),
2589                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_main_outs)
2590                      ));
2591
2592         add_option (_("Solo / mute"), new OptionEditorHeading (_("Send Routing")));
2593
2594         add_option (_("Solo / mute"),
2595              new BoolOption (
2596                      "link-send-and-route-panner",
2597                      _("Link panners of Aux and External Sends with main panner by default"),
2598                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_link_send_and_route_panner),
2599                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_link_send_and_route_panner)
2600                      ));
2601
2602         add_option (_("MIDI"),
2603                     new SpinOption<float> (
2604                             "midi-readahead",
2605                             _("MIDI read-ahead time (seconds)"),
2606                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_readahead),
2607                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_readahead),
2608                             0.1, 10, 0.1, 1,
2609                             "", 1.0, 1
2610                             ));
2611
2612         add_option (_("MIDI"),
2613                     new BoolOption (
2614                             "send-midi-clock",
2615                             _("Send MIDI Clock"),
2616                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_midi_clock),
2617                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_midi_clock)
2618                             ));
2619
2620         add_option (_("MIDI"),
2621                     new BoolOption (
2622                             "send-mtc",
2623                             _("Send MIDI Time Code"),
2624                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mtc),
2625                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mtc)
2626                             ));
2627
2628         add_option (_("MIDI"),
2629                     new SpinOption<int> (
2630                             "mtc-qf-speed-tolerance",
2631                             _("Percentage either side of normal transport speed to transmit MTC"),
2632                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mtc_qf_speed_tolerance),
2633                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mtc_qf_speed_tolerance),
2634                             0, 20, 1, 5
2635                             ));
2636
2637         add_option (_("MIDI"),
2638                     new BoolOption (
2639                             "mmc-control",
2640                             _("Obey MIDI Machine Control commands"),
2641                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_control),
2642                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_control)
2643                             ));
2644
2645         add_option (_("MIDI"),
2646                     new BoolOption (
2647                             "send-mmc",
2648                             _("Send MIDI Machine Control commands"),
2649                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mmc),
2650                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mmc)
2651                             ));
2652
2653         add_option (_("MIDI"),
2654                     new BoolOption (
2655                             "midi-feedback",
2656                             _("Send MIDI control feedback"),
2657                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_feedback),
2658                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_feedback)
2659                             ));
2660
2661         add_option (_("MIDI"),
2662              new SpinOption<uint8_t> (
2663                      "mmc-receive-device-id",
2664                      _("Inbound MMC device ID"),
2665                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_receive_device_id),
2666                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_receive_device_id),
2667                      0, 128, 1, 10
2668                      ));
2669
2670         add_option (_("MIDI"),
2671              new SpinOption<uint8_t> (
2672                      "mmc-send-device-id",
2673                      _("Outbound MMC device ID"),
2674                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_send_device_id),
2675                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_send_device_id),
2676                      0, 128, 1, 10
2677                      ));
2678
2679         add_option (_("MIDI"),
2680              new SpinOption<int32_t> (
2681                      "initial-program-change",
2682                      _("Initial program change"),
2683                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_initial_program_change),
2684                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_initial_program_change),
2685                      -1, 65536, 1, 10
2686                      ));
2687
2688         add_option (_("MIDI"),
2689                     new BoolOption (
2690                             "display-first-midi-bank-as-zero",
2691                             _("Display first MIDI bank/program as 0"),
2692                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_first_midi_bank_is_zero),
2693                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_first_midi_bank_is_zero)
2694                             ));
2695
2696         add_option (_("MIDI"),
2697              new BoolOption (
2698                      "never-display-periodic-midi",
2699                      _("Never display periodic MIDI messages (MTC, MIDI Clock)"),
2700                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_never_display_periodic_midi),
2701                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_never_display_periodic_midi)
2702                      ));
2703
2704         add_option (_("MIDI"),
2705              new BoolOption (
2706                      "sound-midi-notes",
2707                      _("Sound MIDI notes as they are selected"),
2708                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_sound_midi_notes),
2709                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_sound_midi_notes)
2710                      ));
2711
2712         add_option (_("MIDI"), new OptionEditorHeading (_("Midi Audition")));
2713
2714         ComboOption<std::string>* audition_synth = new ComboOption<std::string> (
2715                 "midi-audition-synth-uri",
2716                 _("Midi Audition Synth (LV2)"),
2717                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_audition_synth_uri),
2718                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_audition_synth_uri)
2719                 );
2720
2721         audition_synth->add(X_(""), _("None"));
2722         PluginInfoList all_plugs;
2723         PluginManager& manager (PluginManager::instance());
2724 #ifdef LV2_SUPPORT
2725         all_plugs.insert (all_plugs.end(), manager.lv2_plugin_info().begin(), manager.lv2_plugin_info().end());
2726
2727         for (PluginInfoList::const_iterator i = all_plugs.begin(); i != all_plugs.end(); ++i) {
2728                 if (manager.get_status (*i) == PluginManager::Hidden) continue;
2729                 if (!(*i)->is_instrument()) continue;
2730                 if ((*i)->type != ARDOUR::LV2) continue;
2731                 audition_synth->add((*i)->unique_id, (*i)->name);
2732         }
2733 #endif
2734
2735         add_option (_("MIDI"), audition_synth);
2736
2737         /* USER INTERACTION */
2738
2739         if (
2740 #ifdef PLATFORM_WINDOWS
2741                         true
2742 #else
2743                         getenv ("ARDOUR_BUNDLED")
2744 #endif
2745            )
2746         {
2747                 add_option (_("User interaction"), 
2748                             new BoolOption (
2749                                     "enable-translation",
2750                                     string_compose (_("Use translations of %1 messages\n"
2751                                                       "   <i>(requires a restart of %1 to take effect)</i>\n"
2752                                                       "   <i>(if available for your language preferences)</i>"), PROGRAM_NAME),
2753                                     sigc::ptr_fun (ARDOUR::translations_are_enabled),
2754                                     sigc::ptr_fun (ARDOUR::set_translations_enabled)));
2755         }
2756
2757         add_option (_("User interaction"), new OptionEditorHeading (_("Keyboard")));
2758
2759         add_option (_("User interaction"), new KeyboardOptions);
2760
2761         /* Control Surfaces */
2762
2763         add_option (_("Control Surfaces"), new ControlSurfacesOptions (*this));
2764
2765         ComboOption<RemoteModel>* rm = new ComboOption<RemoteModel> (
2766                 "remote-model",
2767                 _("Control surface remote ID"),
2768                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_remote_model),
2769                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_remote_model)
2770                 );
2771
2772         rm->add (UserOrdered, _("assigned by user"));
2773         rm->add (MixerOrdered, _("follows order of mixer"));
2774
2775         add_option (_("Control Surfaces"), rm);
2776
2777         /* VIDEO Timeline */
2778         add_option (_("Video"), new VideoTimelineOptions (_rc_config));
2779
2780 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined AUDIOUNIT_SUPPORT)
2781         /* Plugin options (currrently VST only) */
2782         add_option (_("Plugins"), new PluginOptions (_rc_config, _ui_config));
2783 #endif
2784
2785         /* INTERFACE */
2786
2787 #ifdef CAIRO_SUPPORTS_FORCE_BUGGY_GRADIENTS_ENVIRONMENT_VARIABLE
2788         BoolOption* bgo = new BoolOption (
2789                 "buggy-gradients",
2790                 _("Possibly improve slow graphical performance"),
2791                 sigc::mem_fun (*_ui_config, &UIConfiguration::get_buggy_gradients),
2792                 sigc::mem_fun (*_ui_config, &UIConfiguration::set_buggy_gradients)
2793                 );
2794
2795         Gtkmm2ext::UI::instance()->set_tip (bgo->tip_widget(), string_compose (_("This requires restarting %1 before having an effect"), PROGRAM_NAME));
2796         add_option (S_("Preferences|GUI"), bgo);
2797 #endif
2798         
2799         add_option (S_("Preferences|GUI"),
2800              new BoolOption (
2801                      "widget-prelight",
2802                      _("Graphically indicate mouse pointer hovering over various widgets"),
2803                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_widget_prelight),
2804                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_widget_prelight)
2805                      ));
2806
2807 #ifdef TOOLTIPS_GOT_FIXED
2808         add_option (S_("Preferences|GUI"),
2809              new BoolOption (
2810                      "use-tooltips",
2811                      _("Show tooltips if mouse hovers over a control"),
2812                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_use_tooltips),
2813                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_use_tooltips)
2814                      ));
2815 #endif
2816
2817         add_option (S_("Preferences|GUI"),
2818              new BoolOption (
2819                      "show-name-highlight",
2820                      _("Use name highlight bars in region displays (requires a restart)"),
2821                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_show_name_highlight),
2822                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_show_name_highlight)
2823                      ));
2824
2825 #ifndef GTKOSX
2826         /* font scaling does nothing with GDK/Quartz */
2827         add_option (S_("Preferences|GUI"), new FontScalingOptions (_ui_config));
2828 #endif
2829
2830         add_option (S_("GUI"),
2831                     new BoolOption (
2832                             "super-rapid-clock-update",
2833                             _("update transport clock display at FPS instead of every 100ms"),
2834                             sigc::mem_fun (*_ui_config, &UIConfiguration::get_super_rapid_clock_update),
2835                             sigc::mem_fun (*_ui_config, &UIConfiguration::set_super_rapid_clock_update)
2836                             ));
2837
2838
2839         /* Image cache size */
2840
2841         Gtk::Adjustment *ics = manage (new Gtk::Adjustment(0, 1, 1024, 10)); /* 1 MB to 1GB in steps of 10MB */
2842         HSliderOption *sics = new HSliderOption("waveform-cache-size",
2843                                                 _("Waveform image cache size (megabytes)"),
2844                                                 ics,
2845                                                 sigc::mem_fun (*ARDOUR_UI::config(), &UIConfiguration::get_waveform_cache_size),
2846                                                 sigc::mem_fun (*ARDOUR_UI::config(), &UIConfiguration::set_waveform_cache_size)
2847                         );
2848         sics->scale().set_digits (0);
2849         Gtkmm2ext::UI::instance()->set_tip
2850                 (sics->tip_widget(),
2851                  _("Increasing the cache size uses more memory to store waveform images, which can improve graphical performance."));
2852         add_option (S_("Preferences|GUI"), sics);
2853         
2854         /* Lock GUI timeout */
2855
2856         Gtk::Adjustment *lts = manage (new Gtk::Adjustment(0, 0, 1000, 1, 10));
2857         HSliderOption *slts = new HSliderOption("lock-gui-after-seconds",
2858                                                 _("Lock timeout (seconds)"),
2859                                                 lts,
2860                                                 sigc::mem_fun (*ARDOUR_UI::config(), &UIConfiguration::get_lock_gui_after_seconds),
2861                                                 sigc::mem_fun (*ARDOUR_UI::config(), &UIConfiguration::set_lock_gui_after_seconds)
2862                         );
2863         slts->scale().set_digits (0);
2864         Gtkmm2ext::UI::instance()->set_tip
2865                 (slts->tip_widget(),
2866                  _("Lock GUI after this many idle seconds (zero to never lock)"));
2867         add_option (S_("Preferences|GUI"), slts);
2868
2869         /* The names of these controls must be the same as those given in MixerStrip
2870            for the actual widgets being controlled.
2871         */
2872         _mixer_strip_visibility.add (0, X_("Input"), _("Input"));
2873         _mixer_strip_visibility.add (0, X_("PhaseInvert"), _("Phase Invert"));
2874         _mixer_strip_visibility.add (0, X_("RecMon"), _("Record & Monitor"));
2875         _mixer_strip_visibility.add (0, X_("SoloIsoLock"), _("Solo Iso / Lock"));
2876         _mixer_strip_visibility.add (0, X_("Output"), _("Output"));
2877         _mixer_strip_visibility.add (0, X_("Comments"), _("Comments"));
2878         
2879         add_option (
2880                 S_("Preferences|GUI"),
2881                 new VisibilityOption (
2882                         _("Mixer Strip"),
2883                         &_mixer_strip_visibility,
2884                         sigc::mem_fun (*_ui_config, &UIConfiguration::get_mixer_strip_visibility),
2885                         sigc::mem_fun (*_ui_config, &UIConfiguration::set_mixer_strip_visibility)
2886                         )
2887                 );
2888
2889         add_option (S_("Preferences|GUI"),
2890              new BoolOption (
2891                      "default-narrow_ms",
2892                      _("Use narrow strips in the mixer by default"),
2893                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_default_narrow_ms),
2894                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_default_narrow_ms)
2895                      ));
2896
2897         add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Metering")));
2898
2899         ComboOption<float>* mht = new ComboOption<float> (
2900                 "meter-hold",
2901                 _("Peak hold time"),
2902                 sigc::mem_fun (*_ui_config, &UIConfiguration::get_meter_hold),
2903                 sigc::mem_fun (*_ui_config, &UIConfiguration::set_meter_hold)
2904                 );
2905
2906         mht->add (MeterHoldOff, _("off"));
2907         mht->add (MeterHoldShort, _("short"));
2908         mht->add (MeterHoldMedium, _("medium"));
2909         mht->add (MeterHoldLong, _("long"));
2910
2911         add_option (S_("Preferences|Metering"), mht);
2912
2913         ComboOption<float>* mfo = new ComboOption<float> (
2914                 "meter-falloff",
2915                 _("DPM fall-off"),
2916                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_falloff),
2917                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_falloff)
2918                 );
2919
2920         mfo->add (METER_FALLOFF_OFF,      _("off"));
2921         mfo->add (METER_FALLOFF_SLOWEST,  _("slowest [6.6dB/sec]"));
2922         mfo->add (METER_FALLOFF_SLOW,     _("slow [8.6dB/sec] (BBC PPM, EBU PPM)"));
2923         mfo->add (METER_FALLOFF_SLOWISH,  _("moderate [12.0dB/sec] (DIN)"));
2924         mfo->add (METER_FALLOFF_MODERATE, _("medium [13.3dB/sec] (EBU Digi PPM, IRT Digi PPM)"));
2925         mfo->add (METER_FALLOFF_MEDIUM,   _("fast [20dB/sec]"));
2926         mfo->add (METER_FALLOFF_FAST,     _("very fast [32dB/sec]"));
2927
2928         add_option (S_("Preferences|Metering"), mfo);
2929
2930         ComboOption<MeterLineUp>* mlu = new ComboOption<MeterLineUp> (
2931                 "meter-line-up-level",
2932                 _("Meter line-up level; 0dBu"),
2933                 sigc::mem_fun (*_ui_config, &UIConfiguration::get_meter_line_up_level),
2934                 sigc::mem_fun (*_ui_config, &UIConfiguration::set_meter_line_up_level)
2935                 );
2936
2937         mlu->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
2938         mlu->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
2939         mlu->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
2940         mlu->add (MeteringLineUp15, _("-15dBFS (DIN)"));
2941
2942         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."));
2943
2944         add_option (S_("Preferences|Metering"), mlu);
2945
2946         ComboOption<MeterLineUp>* mld = new ComboOption<MeterLineUp> (
2947                 "meter-line-up-din",
2948                 _("IEC1/DIN Meter line-up level; 0dBu"),
2949                 sigc::mem_fun (*_ui_config, &UIConfiguration::get_meter_line_up_din),
2950                 sigc::mem_fun (*_ui_config, &UIConfiguration::set_meter_line_up_din)
2951                 );
2952
2953         mld->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
2954         mld->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
2955         mld->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
2956         mld->add (MeteringLineUp15, _("-15dBFS (DIN)"));
2957
2958         Gtkmm2ext::UI::instance()->set_tip (mld->tip_widget(), _("Reference level for IEC1/DIN meter."));
2959
2960         add_option (S_("Preferences|Metering"), mld);
2961
2962         ComboOption<VUMeterStandard>* mvu = new ComboOption<VUMeterStandard> (
2963                 "meter-vu-standard",
2964                 _("VU Meter standard"),
2965                 sigc::mem_fun (*_ui_config, &UIConfiguration::get_meter_vu_standard),
2966                 sigc::mem_fun (*_ui_config, &UIConfiguration::set_meter_vu_standard)
2967                 );
2968
2969         mvu->add (MeteringVUfrench,   _("0VU = -2dBu (France)"));
2970         mvu->add (MeteringVUamerican, _("0VU = 0dBu (North America, Australia)"));
2971         mvu->add (MeteringVUstandard, _("0VU = +4dBu (standard)"));
2972         mvu->add (MeteringVUeight,    _("0VU = +8dBu"));
2973
2974         add_option (S_("Preferences|Metering"), mvu);
2975
2976         Gtk::Adjustment *mpk = manage (new Gtk::Adjustment(0, -10, 0, .1, .1));
2977         HSliderOption *mpks = new HSliderOption("meter-peak",
2978                         _("Peak threshold [dBFS]"),
2979                         mpk,
2980                         sigc::mem_fun (*_ui_config, &UIConfiguration::get_meter_peak),
2981                         sigc::mem_fun (*_ui_config, &UIConfiguration::set_meter_peak)
2982                         );
2983
2984
2985         ComboOption<MeterType>* mtm = new ComboOption<MeterType> (
2986                 "meter-type-master",
2987                 _("Default Meter Type for Master Bus"),
2988                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_master),
2989                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_master)
2990                 );
2991         mtm->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
2992         mtm->add (MeterK20,     ArdourMeter::meter_type_string(MeterK20));
2993         mtm->add (MeterK14,     ArdourMeter::meter_type_string(MeterK14));
2994         mtm->add (MeterK12,     ArdourMeter::meter_type_string(MeterK12));
2995         mtm->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
2996         mtm->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
2997         mtm->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
2998         mtm->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
2999
3000         add_option (S_("Preferences|Metering"), mtm);
3001
3002
3003         ComboOption<MeterType>* mtb = new ComboOption<MeterType> (
3004                 "meter-type-bus",
3005                 _("Default Meter Type for Busses"),
3006                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_bus),
3007                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_bus)
3008                 );
3009         mtb->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
3010         mtb->add (MeterK20,     ArdourMeter::meter_type_string(MeterK20));
3011         mtb->add (MeterK14,     ArdourMeter::meter_type_string(MeterK14));
3012         mtb->add (MeterK12,     ArdourMeter::meter_type_string(MeterK12));
3013         mtb->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
3014         mtb->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
3015         mtb->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
3016         mtb->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
3017
3018         add_option (S_("Preferences|Metering"), mtb);
3019
3020         ComboOption<MeterType>* mtt = new ComboOption<MeterType> (
3021                 "meter-type-track",
3022                 _("Default Meter Type for Tracks"),
3023                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_track),
3024                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_track)
3025                 );
3026         mtt->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
3027         mtt->add (MeterPeak0dB, ArdourMeter::meter_type_string(MeterPeak0dB));
3028
3029         add_option (S_("Preferences|Metering"), mtt);
3030
3031
3032         Gtkmm2ext::UI::instance()->set_tip
3033                 (mpks->tip_widget(),
3034                  _("Specify the audio signal level in dbFS at and above which the meter-peak indicator will flash red."));
3035
3036         add_option (S_("Preferences|Metering"), mpks);
3037
3038         add_option (S_("Preferences|Metering"),
3039              new BoolOption (
3040                      "meter-style-led",
3041                      _("LED meter style"),
3042                      sigc::mem_fun (*_ui_config, &UIConfiguration::get_meter_style_led),
3043                      sigc::mem_fun (*_ui_config, &UIConfiguration::set_meter_style_led)
3044                      ));
3045
3046         /* and now the theme manager */
3047
3048         ThemeManager* tm = manage (new ThemeManager);
3049         add_page (_("Theme"), *tm);
3050 }
3051
3052 void
3053 RCOptionEditor::parameter_changed (string const & p)
3054 {
3055         OptionEditor::parameter_changed (p);
3056
3057         if (p == "use-monitor-bus") {
3058                 bool const s = Config->get_use_monitor_bus ();
3059                 if (!s) {
3060                         /* we can't use this if we don't have a monitor bus */
3061                         Config->set_solo_control_is_listen_control (false);
3062                 }
3063                 _solo_control_is_listen_control->set_sensitive (s);
3064                 _listen_position->set_sensitive (s);
3065         } else if (p == "sync-source") {
3066                 _sync_source->set_sensitive (true);
3067                 if (_session) {
3068                         _sync_source->set_sensitive (!_session->config.get_external_sync());
3069                 }
3070                 switch(Config->get_sync_source()) {
3071                 case ARDOUR::MTC:
3072                 case ARDOUR::LTC:
3073                         _sync_genlock->set_sensitive (true);
3074                         _sync_framerate->set_sensitive (true);
3075                         _sync_source_2997->set_sensitive (true);
3076                         break;
3077                 default:
3078                         _sync_genlock->set_sensitive (false);
3079                         _sync_framerate->set_sensitive (false);
3080                         _sync_source_2997->set_sensitive (false);
3081                         break;
3082                 }
3083         } else if (p == "send-ltc") {
3084                 bool const s = Config->get_send_ltc ();
3085                 _ltc_send_continuously->set_sensitive (s);
3086                 _ltc_volume_slider->set_sensitive (s);
3087         }
3088 }
3089
3090 void RCOptionEditor::ltc_generator_volume_changed () {
3091         _rc_config->set_ltc_output_volume (pow(10, _ltc_volume_adjustment->get_value() / 20));
3092 }
3093
3094 void
3095 RCOptionEditor::populate_sync_options ()
3096 {
3097         vector<SyncSource> sync_opts = ARDOUR::get_available_sync_options ();
3098
3099         _sync_source->clear ();
3100
3101         for (vector<SyncSource>::iterator i = sync_opts.begin(); i != sync_opts.end(); ++i) {
3102                 _sync_source->add (*i, sync_source_to_string (*i));
3103         }
3104
3105         if (sync_opts.empty()) {
3106                 _sync_source->set_sensitive(false);
3107         } else {
3108                 if (std::find(sync_opts.begin(), sync_opts.end(), _rc_config->get_sync_source()) == sync_opts.end()) {
3109                         _rc_config->set_sync_source(sync_opts.front());
3110                 }
3111         }
3112 }