Processor-box control context menu update
[ardour.git] / gtk2_ardour / rc_option_editor.cc
1 /*
2     Copyright (C) 2001-2011 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 #if !defined USE_CAIRO_IMAGE_SURFACE && !defined NDEBUG
25 #define OPTIONAL_CAIRO_IMAGE_SURFACE
26 #endif
27
28 #include <cairo/cairo.h>
29
30 #include <boost/algorithm/string.hpp>
31
32 #include <gtkmm/liststore.h>
33 #include <gtkmm/stock.h>
34 #include <gtkmm/scale.h>
35
36 #include "gtkmm2ext/utils.h"
37 #include "gtkmm2ext/gtk_ui.h"
38 #include "gtkmm2ext/window_title.h"
39
40 #include "pbd/fpu.h"
41 #include "pbd/cpus.h"
42 #include "pbd/i18n.h"
43
44 #include "ardour/audio_backend.h"
45 #include "ardour/audioengine.h"
46 #include "ardour/control_protocol_manager.h"
47 #include "ardour/dB.h"
48 #include "ardour/port_manager.h"
49 #include "ardour/plugin_manager.h"
50 #include "ardour/profile.h"
51 #include "ardour/rc_configuration.h"
52 #include "ardour/transport_master_manager.h"
53
54 #include "control_protocol/control_protocol.h"
55
56 #include "waveview/wave_view.h"
57
58 #include "widgets/paths_dialog.h"
59 #include "widgets/tooltips.h"
60
61 #include "ardour_dialog.h"
62 #include "ardour_ui.h"
63 #include "ardour_window.h"
64 #include "color_theme_manager.h"
65 #include "gui_thread.h"
66 #include "keyboard.h"
67 #include "meter_patterns.h"
68 #include "midi_tracer.h"
69 #include "rc_option_editor.h"
70 #include "sfdb_ui.h"
71 #include "transport_masters_dialog.h"
72 #include "ui_config.h"
73 #include "utils.h"
74
75 using namespace std;
76 using namespace Gtk;
77 using namespace Gtkmm2ext;
78 using namespace PBD;
79 using namespace ARDOUR;
80 using namespace ARDOUR_UI_UTILS;
81 using namespace ArdourWidgets;
82
83 class ClickOptions : public OptionEditorMiniPage
84 {
85 public:
86         ClickOptions (RCConfiguration* c)
87                 : _rc_config (c)
88                 , _click_browse_button (_("Browse..."))
89                 , _click_emphasis_browse_button (_("Browse..."))
90         {
91                 // TODO get rid of GTK -> use OptionEditor Widgets
92                 Table* t = &table;
93                 Label* l;
94                 int row = 0;
95
96                 l = manage (left_aligned_label (_("Emphasis on first beat")));
97                 _use_emphasis_on_click_check_button.add (*l);
98                 t->attach (_use_emphasis_on_click_check_button, 1, 3, row, row + 1, FILL);
99                 _use_emphasis_on_click_check_button.signal_toggled().connect (
100                     sigc::mem_fun (*this, &ClickOptions::use_emphasis_on_click_toggled));
101                 ++row;
102
103                 l = manage (left_aligned_label (_("Use built-in default sounds")));
104                 _use_default_click_check_button.add (*l);
105                 t->attach (_use_default_click_check_button, 1, 3, row, row + 1, FILL);
106                 _use_default_click_check_button.signal_toggled().connect (
107                     sigc::mem_fun (*this, &ClickOptions::use_default_click_toggled));
108                 ++row;
109
110                 l = manage (left_aligned_label (_("Audio file:")));
111                 t->attach (*l, 1, 2, row, row + 1, FILL);
112                 t->attach (_click_path_entry, 2, 3, row, row + 1, FILL);
113                 _click_browse_button.signal_clicked ().connect (
114                     sigc::mem_fun (*this, &ClickOptions::click_browse_clicked));
115                 t->attach (_click_browse_button, 3, 4, row, row + 1, FILL);
116                 ++row;
117
118                 l = manage (left_aligned_label (_("Emphasis audio file:")));
119                 t->attach (*l, 1, 2, row, row + 1, FILL);
120                 t->attach (_click_emphasis_path_entry, 2, 3, row, row + 1, FILL);
121                 _click_emphasis_browse_button.signal_clicked ().connect (
122                     sigc::mem_fun (*this, &ClickOptions::click_emphasis_browse_clicked));
123                 t->attach (_click_emphasis_browse_button, 3, 4, row, row + 1, FILL);
124                 ++row;
125
126                 _click_fader = new FaderOption (
127                                 "click-gain",
128                                 _("Gain level"),
129                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_click_gain),
130                                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_click_gain)
131                                 );
132
133                 _click_fader->add_to_page (this);
134                 _click_fader->set_state_from_config ();
135
136                 _click_path_entry.signal_activate().connect (sigc::mem_fun (*this, &ClickOptions::click_changed));
137                 _click_emphasis_path_entry.signal_activate().connect (sigc::mem_fun (*this, &ClickOptions::click_emphasis_changed));
138
139                 if (_rc_config->get_click_sound ().empty() &&
140                     _rc_config->get_click_emphasis_sound().empty()) {
141                         _use_default_click_check_button.set_active (true);
142                         _use_emphasis_on_click_check_button.set_active (_rc_config->get_use_click_emphasis ());
143
144                 } else {
145                         _use_default_click_check_button.set_active (false);
146                         _use_emphasis_on_click_check_button.set_active (false);
147                 }
148         }
149
150         void parameter_changed (string const & p)
151         {
152                 if (p == "click-sound") {
153                         _click_path_entry.set_text (_rc_config->get_click_sound());
154                 } else if (p == "click-emphasis-sound") {
155                         _click_emphasis_path_entry.set_text (_rc_config->get_click_emphasis_sound());
156                 } else if (p == "use-click-emphasis") {
157                         bool x = _rc_config->get_use_click_emphasis ();
158                         _use_emphasis_on_click_check_button.set_active (x);
159                 } else if (p == "click-gain") {
160                         _click_fader->set_state_from_config ();
161                 }
162         }
163
164         void set_state_from_config ()
165         {
166                 parameter_changed ("click-sound");
167                 parameter_changed ("click-emphasis-sound");
168                 parameter_changed ("use-click-emphasis");
169         }
170
171 private:
172
173         void click_browse_clicked ()
174         {
175                 SoundFileChooser sfdb (_("Choose Click"));
176
177                 sfdb.show_all ();
178                 sfdb.present ();
179
180                 if (sfdb.run () == RESPONSE_OK) {
181                         click_chosen (sfdb.get_filename());
182                 }
183         }
184
185         void click_chosen (string const & path)
186         {
187                 _click_path_entry.set_text (path);
188                 _rc_config->set_click_sound (path);
189         }
190
191         void click_changed ()
192         {
193                 click_chosen (_click_path_entry.get_text ());
194         }
195
196         void click_emphasis_browse_clicked ()
197         {
198                 SoundFileChooser sfdb (_("Choose Click Emphasis"));
199
200                 sfdb.show_all ();
201                 sfdb.present ();
202
203                 if (sfdb.run () == RESPONSE_OK) {
204                         click_emphasis_chosen (sfdb.get_filename());
205                 }
206         }
207
208         void click_emphasis_chosen (string const & path)
209         {
210                 _click_emphasis_path_entry.set_text (path);
211                 _rc_config->set_click_emphasis_sound (path);
212         }
213
214         void click_emphasis_changed ()
215         {
216                 click_emphasis_chosen (_click_emphasis_path_entry.get_text ());
217         }
218
219         void use_default_click_toggled ()
220         {
221                 if (_use_default_click_check_button.get_active ()) {
222                         _rc_config->set_click_sound ("");
223                         _rc_config->set_click_emphasis_sound ("");
224                         _click_path_entry.set_sensitive (false);
225                         _click_emphasis_path_entry.set_sensitive (false);
226                         _click_browse_button.set_sensitive (false);
227                         _click_emphasis_browse_button.set_sensitive (false);
228                 } else {
229                         _click_path_entry.set_sensitive (true);
230                         _click_emphasis_path_entry.set_sensitive (true);
231                         _click_browse_button.set_sensitive (true);
232                         _click_emphasis_browse_button.set_sensitive (true);
233                 }
234         }
235
236         void use_emphasis_on_click_toggled ()
237         {
238                 if (_use_emphasis_on_click_check_button.get_active ()) {
239                         _rc_config->set_use_click_emphasis(true);
240                 } else {
241                         _rc_config->set_use_click_emphasis(false);
242                 }
243         }
244
245         RCConfiguration* _rc_config;
246         CheckButton _use_default_click_check_button;
247         CheckButton _use_emphasis_on_click_check_button;
248         Entry _click_path_entry;
249         Entry _click_emphasis_path_entry;
250         Button _click_browse_button;
251         Button _click_emphasis_browse_button;
252         FaderOption* _click_fader;
253 };
254
255 class UndoOptions : public OptionEditorComponent
256 {
257 public:
258         UndoOptions (RCConfiguration* c) :
259                 _rc_config (c),
260                 _limit_undo_button (_("Limit undo history to")),
261                 _save_undo_button (_("Save undo history of"))
262         {
263                 // TODO get rid of GTK -> use OptionEditor SpinOption
264                 _limit_undo_spin.set_range (0, 512);
265                 _limit_undo_spin.set_increments (1, 10);
266
267                 _save_undo_spin.set_range (0, 512);
268                 _save_undo_spin.set_increments (1, 10);
269
270                 _limit_undo_button.signal_toggled().connect (sigc::mem_fun (*this, &UndoOptions::limit_undo_toggled));
271                 _limit_undo_spin.signal_value_changed().connect (sigc::mem_fun (*this, &UndoOptions::limit_undo_changed));
272                 _save_undo_button.signal_toggled().connect (sigc::mem_fun (*this, &UndoOptions::save_undo_toggled));
273                 _save_undo_spin.signal_value_changed().connect (sigc::mem_fun (*this, &UndoOptions::save_undo_changed));
274         }
275
276         void parameter_changed (string const & p)
277         {
278                 if (p == "history-depth") {
279                         int32_t const d = _rc_config->get_history_depth();
280                         _limit_undo_button.set_active (d != 0);
281                         _limit_undo_spin.set_sensitive (d != 0);
282                         _limit_undo_spin.set_value (d);
283                 } else if (p == "save-history") {
284                         bool const x = _rc_config->get_save_history ();
285                         _save_undo_button.set_active (x);
286                         _save_undo_spin.set_sensitive (x);
287                 } else if (p == "save-history-depth") {
288                         _save_undo_spin.set_value (_rc_config->get_saved_history_depth());
289                 }
290         }
291
292         void set_state_from_config ()
293         {
294                 parameter_changed ("save-history");
295                 parameter_changed ("history-depth");
296                 parameter_changed ("save-history-depth");
297         }
298
299         void limit_undo_toggled ()
300         {
301                 bool const x = _limit_undo_button.get_active ();
302                 _limit_undo_spin.set_sensitive (x);
303                 int32_t const n = x ? 16 : 0;
304                 _limit_undo_spin.set_value (n);
305                 _rc_config->set_history_depth (n);
306         }
307
308         void limit_undo_changed ()
309         {
310                 _rc_config->set_history_depth (_limit_undo_spin.get_value_as_int ());
311         }
312
313         void save_undo_toggled ()
314         {
315                 bool const x = _save_undo_button.get_active ();
316                 _rc_config->set_save_history (x);
317         }
318
319         void save_undo_changed ()
320         {
321                 _rc_config->set_saved_history_depth (_save_undo_spin.get_value_as_int ());
322         }
323
324         void add_to_page (OptionEditorPage* p)
325         {
326                 int const n = p->table.property_n_rows();
327                 Table* t = & p->table;
328
329                 t->resize (n + 2, 3);
330
331                 Label* l = manage (left_aligned_label (_("commands")));
332                 HBox* box = manage (new HBox());
333                 box->set_spacing (4);
334                 box->pack_start (_limit_undo_spin, false, false);
335                 box->pack_start (*l, true, true);
336                 t->attach (_limit_undo_button, 1, 2, n, n +1, FILL);
337                 t->attach (*box, 2, 3, n, n + 1, FILL | EXPAND);
338
339                 l = manage (left_aligned_label (_("commands")));
340                 box = manage (new HBox());
341                 box->set_spacing (4);
342                 box->pack_start (_save_undo_spin, false, false);
343                 box->pack_start (*l, true, true);
344                 t->attach (_save_undo_button, 1, 2, n + 1, n + 2, FILL);
345                 t->attach (*box, 2, 3, n + 1, n + 2, FILL | EXPAND);
346         }
347
348         Gtk::Widget& tip_widget() {
349                 return _limit_undo_button; // unused
350         }
351
352 private:
353         RCConfiguration* _rc_config;
354         CheckButton _limit_undo_button;
355         SpinButton _limit_undo_spin;
356         CheckButton _save_undo_button;
357         SpinButton _save_undo_spin;
358 };
359
360
361 static const struct {
362         const char *name;
363         guint modifier;
364 } modifiers[] = {
365
366         { "Unmodified", 0 },
367
368 #ifdef __APPLE__
369
370         /* Command = Meta
371            Option/Alt = Mod1
372         */
373         { "Key|Shift", GDK_SHIFT_MASK },
374         { "Command", GDK_MOD2_MASK },
375         { "Control", GDK_CONTROL_MASK },
376         { "Option", GDK_MOD1_MASK },
377         { "Command-Shift", GDK_MOD2_MASK|GDK_SHIFT_MASK },
378         { "Command-Option", GDK_MOD2_MASK|GDK_MOD1_MASK },
379         { "Command-Control", GDK_MOD2_MASK|GDK_CONTROL_MASK },
380         { "Command-Option-Control", GDK_MOD2_MASK|GDK_MOD1_MASK|GDK_CONTROL_MASK },
381         { "Option-Control", GDK_MOD1_MASK|GDK_CONTROL_MASK },
382         { "Option-Shift", GDK_MOD1_MASK|GDK_SHIFT_MASK },
383         { "Control-Shift", GDK_CONTROL_MASK|GDK_SHIFT_MASK },
384         { "Shift-Command-Option", GDK_MOD5_MASK|GDK_SHIFT_MASK|GDK_MOD2_MASK },
385
386 #else
387         { "Key|Shift", GDK_SHIFT_MASK },
388         { "Control", GDK_CONTROL_MASK },
389         { "Alt", GDK_MOD1_MASK },
390         { "Control-Shift", GDK_CONTROL_MASK|GDK_SHIFT_MASK },
391         { "Control-Alt", GDK_CONTROL_MASK|GDK_MOD1_MASK },
392         { "Control-Windows", GDK_CONTROL_MASK|GDK_MOD4_MASK },
393         { "Control-Shift-Alt", GDK_CONTROL_MASK|GDK_SHIFT_MASK|GDK_MOD1_MASK },
394         { "Alt-Windows", GDK_MOD1_MASK|GDK_MOD4_MASK },
395         { "Alt-Shift", GDK_MOD1_MASK|GDK_SHIFT_MASK },
396         { "Alt-Shift-Windows", GDK_MOD1_MASK|GDK_SHIFT_MASK|GDK_MOD4_MASK },
397         { "Mod2", GDK_MOD2_MASK },
398         { "Mod3", GDK_MOD3_MASK },
399         { "Windows", GDK_MOD4_MASK },
400         { "Mod5", GDK_MOD5_MASK },
401 #endif
402         { 0, 0 }
403 };
404
405
406 class KeyboardOptions : public OptionEditorMiniPage
407 {
408 public:
409         KeyboardOptions ()
410                 : _delete_button_adjustment (3, 1, 12)
411                 , _delete_button_spin (_delete_button_adjustment)
412                 , _edit_button_adjustment (3, 1, 5)
413                 , _edit_button_spin (_edit_button_adjustment)
414                 , _insert_note_button_adjustment (3, 1, 5)
415                 , _insert_note_button_spin (_insert_note_button_adjustment)
416         {
417                 // TODO get rid of GTK -> use OptionEditor Widgets
418
419                 const std::string restart_msg = _("\nChanges to this setting will only persist after your project has been saved.");
420                 /* internationalize and prepare for use with combos */
421
422                 vector<string> dumb;
423                 for (int i = 0; modifiers[i].name; ++i) {
424                         dumb.push_back (S_(modifiers[i].name));
425                 }
426
427                 set_popdown_strings (_edit_modifier_combo, dumb);
428                 _edit_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::edit_modifier_chosen));
429                 Gtkmm2ext::UI::instance()->set_tip (_edit_modifier_combo,
430                                 (string_compose (_("<b>Recommended Setting: %1 + button 3 (right mouse button)</b>%2"),  Keyboard::primary_modifier_name (), restart_msg)));
431
432                 Table* t = &table;
433
434                 int row = 0;
435                 int col = 0;
436
437                 Label* l = manage (left_aligned_label (_("Select Keyboard layout:")));
438                 l->set_name ("OptionsLabel");
439
440                 vector<string> strs;
441
442                 for (map<string,string>::iterator bf = Keyboard::binding_files.begin(); bf != Keyboard::binding_files.end(); ++bf) {
443                         strs.push_back (bf->first);
444                 }
445
446                 set_popdown_strings (_keyboard_layout_selector, strs);
447                 _keyboard_layout_selector.set_active_text (Keyboard::current_binding_name());
448                 _keyboard_layout_selector.signal_changed().connect (sigc::mem_fun (*this, &KeyboardOptions::bindings_changed));
449
450                 t->attach (*l, col + 1, col + 2, row, row + 1, FILL, FILL);
451                 t->attach (_keyboard_layout_selector, col + 2, col + 3, row, row + 1, FILL | EXPAND, FILL);
452
453                 ++row;
454                 col = 0;
455
456                 l = manage (left_aligned_label (string_compose ("<b>%1</b>", _("When Clicking:"))));
457                 l->set_name ("OptionEditorHeading");
458                 l->set_use_markup (true);
459                 t->attach (*l, col, col + 2, row, row + 1, FILL | EXPAND, FILL);
460
461                 ++row;
462                 col = 1;
463
464                 l = manage (left_aligned_label (_("Edit using:")));
465                 l->set_name ("OptionsLabel");
466
467                 t->attach (*l, col, col + 1, row, row + 1, FILL, FILL);
468                 t->attach (_edit_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
469
470                 l = manage (new Label (_("+ button")));
471                 l->set_name ("OptionsLabel");
472
473                 t->attach (*l, col + 3, col + 4, row, row + 1, FILL, FILL);
474                 t->attach (_edit_button_spin, col + 4, col + 5, row, row + 1, SHRINK , FILL);
475
476                 _edit_button_spin.set_name ("OptionsEntry");
477                 _edit_button_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::edit_button_changed));
478
479                 ++row;
480                 col = 1;
481
482                 set_popdown_strings (_delete_modifier_combo, dumb);
483                 _delete_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::delete_modifier_chosen));
484                 Gtkmm2ext::UI::instance()->set_tip (_delete_modifier_combo,
485                                 (string_compose (_("<b>Recommended Setting: %1 + button 3 (right mouse button)</b>%2"), Keyboard::tertiary_modifier_name (), restart_msg)));
486
487                 l = manage (left_aligned_label (_("Delete using:")));
488                 l->set_name ("OptionsLabel");
489
490                 t->attach (*l, col, col + 1, row, row + 1, FILL, FILL);
491                 t->attach (_delete_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
492
493                 l = manage (new Label (_("+ button")));
494                 l->set_name ("OptionsLabel");
495
496                 t->attach (*l, col + 3, col + 4, row, row + 1, FILL, FILL);
497                 t->attach (_delete_button_spin, col + 4, col + 5, row, row + 1, SHRINK, FILL);
498
499                 _delete_button_spin.set_name ("OptionsEntry");
500                 _delete_button_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::delete_button_changed));
501
502                 ++row;
503                 col = 1;
504
505                 set_popdown_strings (_insert_note_modifier_combo, dumb);
506                 _insert_note_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::insert_note_modifier_chosen));
507                 Gtkmm2ext::UI::instance()->set_tip (_insert_note_modifier_combo,
508                                 (string_compose (_("<b>Recommended Setting: %1 + button 1 (left mouse button)</b>%2"), Keyboard::primary_modifier_name (), restart_msg)));
509
510                 l = manage (left_aligned_label (_("Insert note using:")));
511                 l->set_name ("OptionsLabel");
512
513                 t->attach (*l, col, col + 1, row, row + 1, FILL, FILL);
514                 t->attach (_insert_note_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
515
516                 l = manage (new Label (_("+ button")));
517                 l->set_name ("OptionsLabel");
518
519                 t->attach (*l, col + 3, col + 4, row, row + 1, FILL, FILL);
520                 t->attach (_insert_note_button_spin, col + 4, col + 5, row, row + 1, SHRINK, FILL);
521
522                 _insert_note_button_spin.set_name ("OptionsEntry");
523                 _insert_note_button_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::insert_note_button_changed));
524
525                 ++row;
526
527                 l = manage (left_aligned_label (string_compose ("<b>%1</b>", _("When Beginning a Drag:"))));
528                 l->set_name ("OptionEditorHeading");
529                 l->set_use_markup (true);
530                 t->attach (*l, 0, 2, row, row + 1, FILL | EXPAND, FILL);
531
532                 ++row;
533                 col = 1;
534
535                 /* copy modifier */
536                 set_popdown_strings (_copy_modifier_combo, dumb);
537                 _copy_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::copy_modifier_chosen));
538                 Gtkmm2ext::UI::instance()->set_tip (_copy_modifier_combo,
539                                                     (string_compose (_("<b>Recommended Setting: %1</b>%2"),
540 #ifdef __APPLE__
541                                                                      Keyboard::secondary_modifier_name (),
542 #else
543                                                                      Keyboard::primary_modifier_name (),
544 #endif
545                                                                      restart_msg)));
546
547                 l = manage (left_aligned_label (_("Copy items using:")));
548                 l->set_name ("OptionsLabel");
549
550                 t->attach (*l, col, col + 1, row, row + 1, FILL, FILL);
551                 t->attach (_copy_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
552
553                                 ++row;
554                 col = 1;
555
556                 /* constraint modifier */
557                 set_popdown_strings (_constraint_modifier_combo, dumb);
558                 _constraint_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::constraint_modifier_chosen));
559                 Gtkmm2ext::UI::instance()->set_tip (_constraint_modifier_combo,
560                                                     (string_compose (_("<b>Recommended Setting: %1</b>%2"),
561 #ifdef __APPLE__
562                                                                      Keyboard::primary_modifier_name (),
563 #else
564                                                                      Keyboard::tertiary_modifier_name (),
565 #endif
566                                                                      restart_msg)));
567
568                 l = manage (left_aligned_label (_("Constrain drag using:")));
569                 l->set_name ("OptionsLabel");
570
571                 t->attach (*l, col, col + 1, row, row + 1, FILL, FILL);
572                 t->attach (_constraint_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
573
574                 ++row;
575                 col = 1;
576
577                 /* push points */
578                 set_popdown_strings (_push_points_combo, dumb);
579                 _push_points_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::push_points_modifier_chosen));
580
581                 std::string mod_str = string_compose (X_("%1-%2"), Keyboard::primary_modifier_name (), Keyboard::level4_modifier_name ());
582                 Gtkmm2ext::UI::instance()->set_tip (_push_points_combo,
583                                 (string_compose (_("<b>Recommended Setting: %1</b>%2"), mod_str, restart_msg)));
584
585                 l = manage (left_aligned_label (_("Push points using:")));
586                 l->set_name ("OptionsLabel");
587
588                 t->attach (*l, col, col + 1, row, row + 1, FILL, FILL);
589                 t->attach (_push_points_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
590
591                 ++row;
592
593                 l = manage (left_aligned_label (string_compose ("<b>%1</b>", _("When Beginning a Trim:"))));
594                 l->set_name ("OptionEditorHeading");
595                 l->set_use_markup (true);
596                 t->attach (*l, 0, 2, row, row + 1, FILL | EXPAND, FILL);
597
598                 ++row;
599                 col = 1;
600
601                 /* trim_contents */
602                 set_popdown_strings (_trim_contents_combo, dumb);
603                 _trim_contents_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::trim_contents_modifier_chosen));
604                 Gtkmm2ext::UI::instance()->set_tip (_trim_contents_combo,
605                                 (string_compose (_("<b>Recommended Setting: %1</b>%2"), Keyboard::primary_modifier_name (), restart_msg)));
606
607                 l = manage (left_aligned_label (_("Trim contents using:")));
608                 l->set_name ("OptionsLabel");
609
610                 t->attach (*l, col, col + 1, row, row + 1, FILL, FILL);
611                 t->attach (_trim_contents_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
612
613                 ++row;
614                 col = 1;
615
616                 /* anchored trim */
617                 set_popdown_strings (_trim_anchored_combo, dumb);
618                 _trim_anchored_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::trim_anchored_modifier_chosen));
619
620                 mod_str = string_compose (X_("%1-%2"), Keyboard::primary_modifier_name (), Keyboard::tertiary_modifier_name ());
621                 Gtkmm2ext::UI::instance()->set_tip (_trim_anchored_combo,
622                                 (string_compose (_("<b>Recommended Setting: %1</b>%2"), mod_str, restart_msg)));
623
624                 l = manage (left_aligned_label (_("Anchored trim using:")));
625                 l->set_name ("OptionsLabel");
626
627                 t->attach (*l, col, col + 1, row, row + 1, FILL, FILL);
628                 ++col;
629                 t->attach (_trim_anchored_combo, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
630
631                 ++row;
632                 col = 1;
633
634                 /* jump trim disabled for now
635                 set_popdown_strings (_trim_jump_combo, dumb);
636                 _trim_jump_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::trim_jump_modifier_chosen));
637
638                 l = manage (left_aligned_label (_("Jump after trim using:")));
639                 l->set_name ("OptionsLabel");
640
641                 t->attach (*l, col, col + 1, row, row + 1, FILL, FILL);
642                 ++col;
643                 t->attach (_trim_jump_combo, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
644
645                 ++row;
646                 col = 1;
647                 */
648
649                 /* note resize relative */
650                 set_popdown_strings (_note_size_relative_combo, dumb);
651                 _note_size_relative_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::note_size_relative_modifier_chosen));
652                 Gtkmm2ext::UI::instance()->set_tip (_note_size_relative_combo,
653                                 (string_compose (_("<b>Recommended Setting: %1</b>%2"), Keyboard::tertiary_modifier_name (), restart_msg))); // XXX 2ndary
654
655                 l = manage (left_aligned_label (_("Resize notes relatively using:")));
656                 l->set_name ("OptionsLabel");
657
658                 t->attach (*l, col, col + 1, row, row + 1, FILL, FILL);
659                 ++col;
660                 t->attach (_note_size_relative_combo, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
661
662                 ++row;
663
664                 l = manage (left_aligned_label (string_compose ("<b>%1</b>", _("While Dragging:"))));
665                 l->set_name ("OptionEditorHeading");
666                 l->set_use_markup (true);
667                 t->attach (*l, 0, 2, row, row + 1, FILL | EXPAND, FILL);
668
669                 ++row;
670                 col = 1;
671
672                 /* ignore snap */
673                 set_popdown_strings (_snap_modifier_combo, dumb);
674                 _snap_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::snap_modifier_chosen));
675 #ifdef __APPLE__
676                 mod_str = string_compose (X_("%1-%2"), Keyboard::level4_modifier_name (), Keyboard::tertiary_modifier_name ());
677 #else
678                 mod_str = Keyboard::secondary_modifier_name();
679 #endif
680                 Gtkmm2ext::UI::instance()->set_tip (_snap_modifier_combo,
681                                 (string_compose (_("<b>Recommended Setting: %1</b>%2"), mod_str, restart_msg)));
682
683                 l = manage (left_aligned_label (_("Ignore snap using:")));
684                 l->set_name ("OptionsLabel");
685
686                 t->attach (*l, col, col + 1, row, row + 1, FILL, FILL);
687                 t->attach (_snap_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
688
689                 ++row;
690                 col = 1;
691
692                 /* snap delta */
693                 set_popdown_strings (_snap_delta_combo, dumb);
694                 _snap_delta_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::snap_delta_modifier_chosen));
695 #ifdef __APPLE__
696                 mod_str = Keyboard::level4_modifier_name ();
697 #else
698                 mod_str = string_compose (X_("%1-%2"), Keyboard::secondary_modifier_name (), Keyboard::level4_modifier_name ());
699 #endif
700                 Gtkmm2ext::UI::instance()->set_tip (_snap_delta_combo,
701                                 (string_compose (_("<b>Recommended Setting: %1</b>%2"), mod_str, restart_msg)));
702
703                 l = manage (left_aligned_label (_("Snap relatively using:")));
704                 l->set_name ("OptionsLabel");
705
706                 t->attach (*l, col, col + 1, row, row + 1, FILL, FILL);
707                 t->attach (_snap_delta_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
708
709                 ++row;
710
711                 l = manage (left_aligned_label (string_compose ("<b>%1</b>", _("While Trimming:"))));
712                 l->set_name ("OptionEditorHeading");
713                 l->set_use_markup (true);
714                 t->attach (*l, 0, 2, row, row + 1, FILL | EXPAND, FILL);
715
716                 ++row;
717                 col = 1;
718
719                 /* trim_overlap */
720                 set_popdown_strings (_trim_overlap_combo, dumb);
721                 _trim_overlap_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::trim_overlap_modifier_chosen));
722
723                 Gtkmm2ext::UI::instance()->set_tip (_trim_overlap_combo,
724                                 (string_compose (_("<b>Recommended Setting: %1</b>%2"), Keyboard::tertiary_modifier_name (), restart_msg)));
725
726                 l = manage (left_aligned_label (_("Resize overlapped regions using:")));
727                 l->set_name ("OptionsLabel");
728
729                 t->attach (*l, col, col + 1, row, row + 1, FILL, FILL);
730                 t->attach (_trim_overlap_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
731
732                 ++row;
733
734                 l = manage (left_aligned_label (string_compose ("<b>%1</b>", _("While Dragging Control Points:"))));
735                 l->set_name ("OptionEditorHeading");
736                 l->set_use_markup (true);
737                 t->attach (*l, 0, 2, row, row + 1, FILL | EXPAND, FILL);
738
739                 ++row;
740                 col = 1;
741
742                 /* fine adjust */
743                 set_popdown_strings (_fine_adjust_combo, dumb);
744                 _fine_adjust_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::fine_adjust_modifier_chosen));
745
746                 mod_str = string_compose (X_("%1-%2"), Keyboard::primary_modifier_name (), Keyboard::secondary_modifier_name ()); // XXX just 2ndary ?!
747                 Gtkmm2ext::UI::instance()->set_tip (_fine_adjust_combo,
748                                 (string_compose (_("<b>Recommended Setting: %1</b>%2"), mod_str, restart_msg)));
749
750                 l = manage (left_aligned_label (_("Fine adjust using:")));
751                 l->set_name ("OptionsLabel");
752
753                 t->attach (*l, col, col + 1, row, row + 1, FILL, FILL);
754                 t->attach (_fine_adjust_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
755
756                 OptionEditorHeading* h = new OptionEditorHeading (_("Reset"));
757                 h->add_to_page (this);
758
759                 RcActionButton* rb = new RcActionButton (_("Reset to recommended defaults"),
760                                 sigc::mem_fun (*this, &KeyboardOptions::reset_to_defaults));
761                 rb->add_to_page (this);
762
763                 set_state_from_config ();
764         }
765
766         void parameter_changed (string const &)
767         {
768                 /* XXX: these aren't really config options... */
769         }
770
771         void set_state_from_config ()
772         {
773                 _delete_button_adjustment.set_value (Keyboard::delete_button());
774                 _insert_note_button_adjustment.set_value (Keyboard::insert_note_button());
775                 _edit_button_adjustment.set_value (Keyboard::edit_button());
776
777                 for (int x = 0; modifiers[x].name; ++x) {
778                         if (modifiers[x].modifier == (guint) ArdourKeyboard::trim_overlap_modifier ()) {
779                                 _trim_overlap_combo.set_active_text (S_(modifiers[x].name));
780                         }
781                         if (modifiers[x].modifier == Keyboard::delete_modifier ()) {
782                                 _delete_modifier_combo.set_active_text (S_(modifiers[x].name));
783                         }
784                         if (modifiers[x].modifier == Keyboard::edit_modifier ()) {
785                                 _edit_modifier_combo.set_active_text (S_(modifiers[x].name));
786                         }
787                         if (modifiers[x].modifier == Keyboard::insert_note_modifier ()) {
788                                 _insert_note_modifier_combo.set_active_text (S_(modifiers[x].name));
789                         }
790                         if (modifiers[x].modifier == (guint) Keyboard::CopyModifier) {
791                                 _copy_modifier_combo.set_active_text (S_(modifiers[x].name));
792                         }
793                         if (modifiers[x].modifier == (guint) ArdourKeyboard::constraint_modifier ()) {
794                                 _constraint_modifier_combo.set_active_text (S_(modifiers[x].name));
795                         }
796                         if (modifiers[x].modifier == (guint) ArdourKeyboard::push_points_modifier ()) {
797                                 _push_points_combo.set_active_text (S_(modifiers[x].name));
798                         }
799                         if (modifiers[x].modifier == (guint) ArdourKeyboard::trim_contents_modifier ()) {
800                                 _trim_contents_combo.set_active_text (S_(modifiers[x].name));
801                         }
802                         if (modifiers[x].modifier == (guint) ArdourKeyboard::trim_anchored_modifier ()) {
803                                 _trim_anchored_combo.set_active_text (S_(modifiers[x].name));
804                         }
805 #if 0
806                         if (modifiers[x].modifier == (guint) Keyboard::trim_jump_modifier ()) {
807                                 _trim_jump_combo.set_active_text (S_(modifiers[x].name));
808                         }
809 #endif
810                         if (modifiers[x].modifier == (guint) ArdourKeyboard::note_size_relative_modifier ()) {
811                                 _note_size_relative_combo.set_active_text (S_(modifiers[x].name));
812                         }
813                         if (modifiers[x].modifier == (guint) Keyboard::snap_modifier ()) {
814                                 _snap_modifier_combo.set_active_text (S_(modifiers[x].name));
815                         }
816                         if (modifiers[x].modifier == (guint) Keyboard::snap_delta_modifier ()) {
817                                 _snap_delta_combo.set_active_text (S_(modifiers[x].name));
818                         }
819                         if (modifiers[x].modifier == (guint) ArdourKeyboard::fine_adjust_modifier ()) {
820                                 _fine_adjust_combo.set_active_text (S_(modifiers[x].name));
821                         }
822                 }
823         }
824
825         void add_to_page (OptionEditorPage* p)
826         {
827                 int const n = p->table.property_n_rows();
828                 p->table.resize (n + 1, 3);
829                 p->table.attach (box, 1, 3, n, n + 1, FILL | EXPAND, SHRINK, 0, 0);
830         }
831
832 private:
833
834         void bindings_changed ()
835         {
836                 string const txt = _keyboard_layout_selector.get_active_text();
837
838                 /* XXX: config...?  for all this keyboard stuff */
839
840                 for (map<string,string>::iterator i = Keyboard::binding_files.begin(); i != Keyboard::binding_files.end(); ++i) {
841                         if (txt == i->first) {
842                                 if (Keyboard::load_keybindings (i->second)) {
843                                         Keyboard::save_keybindings ();
844                                 }
845                         }
846                 }
847         }
848
849         void edit_modifier_chosen ()
850         {
851                 string const txt = _edit_modifier_combo.get_active_text();
852
853                 for (int i = 0; modifiers[i].name; ++i) {
854                         if (txt == S_(modifiers[i].name)) {
855                                 Keyboard::set_edit_modifier (modifiers[i].modifier);
856                                 break;
857                         }
858                 }
859         }
860
861         void delete_modifier_chosen ()
862         {
863                 string const txt = _delete_modifier_combo.get_active_text();
864
865                 for (int i = 0; modifiers[i].name; ++i) {
866                         if (txt == S_(modifiers[i].name)) {
867                                 Keyboard::set_delete_modifier (modifiers[i].modifier);
868                                 break;
869                         }
870                 }
871         }
872
873         void copy_modifier_chosen ()
874         {
875                 string const txt = _copy_modifier_combo.get_active_text();
876
877                 for (int i = 0; modifiers[i].name; ++i) {
878                         if (txt == S_(modifiers[i].name)) {
879                                 Keyboard::set_copy_modifier (modifiers[i].modifier);
880                                 break;
881                         }
882                 }
883         }
884
885         void insert_note_modifier_chosen ()
886         {
887                 string const txt = _insert_note_modifier_combo.get_active_text();
888
889                 for (int i = 0; modifiers[i].name; ++i) {
890                         if (txt == S_(modifiers[i].name)) {
891                                 Keyboard::set_insert_note_modifier (modifiers[i].modifier);
892                                 break;
893                         }
894                 }
895         }
896
897         void snap_modifier_chosen ()
898         {
899                 string const txt = _snap_modifier_combo.get_active_text();
900
901                 for (int i = 0; modifiers[i].name; ++i) {
902                         if (txt == S_(modifiers[i].name)) {
903                                 Keyboard::set_snap_modifier (modifiers[i].modifier);
904                                 break;
905                         }
906                 }
907         }
908
909         void snap_delta_modifier_chosen ()
910         {
911                 string const txt = _snap_delta_combo.get_active_text();
912
913                 for (int i = 0; modifiers[i].name; ++i) {
914                         if (txt == S_(modifiers[i].name)) {
915                                 Keyboard::set_snap_delta_modifier (modifiers[i].modifier);
916                                 break;
917                         }
918                 }
919         }
920
921         void constraint_modifier_chosen ()
922         {
923                 string const txt = _constraint_modifier_combo.get_active_text();
924
925                 for (int i = 0; modifiers[i].name; ++i) {
926                         if (txt == S_(modifiers[i].name)) {
927                                 ArdourKeyboard::set_constraint_modifier (modifiers[i].modifier);
928                                 break;
929                         }
930                 }
931         }
932
933         void trim_contents_modifier_chosen ()
934         {
935                 string const txt = _trim_contents_combo.get_active_text();
936
937                 for (int i = 0; modifiers[i].name; ++i) {
938                         if (txt == S_(modifiers[i].name)) {
939                                 ArdourKeyboard::set_trim_contents_modifier (modifiers[i].modifier);
940                                 break;
941                         }
942                 }
943         }
944
945         void trim_overlap_modifier_chosen ()
946         {
947                 string const txt = _trim_overlap_combo.get_active_text();
948
949                 for (int i = 0; modifiers[i].name; ++i) {
950                         if (txt == S_(modifiers[i].name)) {
951                                 ArdourKeyboard::set_trim_overlap_modifier (modifiers[i].modifier);
952                                 break;
953                         }
954                 }
955         }
956
957         void trim_anchored_modifier_chosen ()
958         {
959                 string const txt = _trim_anchored_combo.get_active_text();
960
961                 for (int i = 0; modifiers[i].name; ++i) {
962                         if (txt == S_(modifiers[i].name)) {
963                                 ArdourKeyboard::set_trim_anchored_modifier (modifiers[i].modifier);
964                                 break;
965                         }
966                 }
967         }
968
969         void fine_adjust_modifier_chosen ()
970         {
971                 string const txt = _fine_adjust_combo.get_active_text();
972
973                 for (int i = 0; modifiers[i].name; ++i) {
974                         if (txt == S_(modifiers[i].name)) {
975                                 ArdourKeyboard::set_fine_adjust_modifier (modifiers[i].modifier);
976                                 break;
977                         }
978                 }
979         }
980
981         void push_points_modifier_chosen ()
982         {
983                 string const txt = _push_points_combo.get_active_text();
984
985                 for (int i = 0; modifiers[i].name; ++i) {
986                         if (txt == S_(modifiers[i].name)) {
987                                 ArdourKeyboard::set_push_points_modifier (modifiers[i].modifier);
988                                 break;
989                         }
990                 }
991         }
992
993         void note_size_relative_modifier_chosen ()
994         {
995                 string const txt = _note_size_relative_combo.get_active_text();
996
997                 for (int i = 0; modifiers[i].name; ++i) {
998                         if (txt == S_(modifiers[i].name)) {
999                                 ArdourKeyboard::set_note_size_relative_modifier (modifiers[i].modifier);
1000                                 break;
1001                         }
1002                 }
1003         }
1004
1005         void delete_button_changed ()
1006         {
1007                 Keyboard::set_delete_button (_delete_button_spin.get_value_as_int());
1008         }
1009
1010         void edit_button_changed ()
1011         {
1012                 Keyboard::set_edit_button (_edit_button_spin.get_value_as_int());
1013         }
1014
1015         void insert_note_button_changed ()
1016         {
1017                 Keyboard::set_insert_note_button (_insert_note_button_spin.get_value_as_int());
1018         }
1019
1020         void reset_to_defaults ()
1021         {
1022                 /* when clicking*/
1023                 Keyboard::set_edit_modifier (Keyboard::PrimaryModifier);
1024                 Keyboard::set_edit_button (3);
1025                 Keyboard::set_delete_modifier (Keyboard::TertiaryModifier);
1026                 Keyboard::set_delete_button (3);
1027                 Keyboard::set_insert_note_modifier (Keyboard::PrimaryModifier);
1028                 Keyboard::set_insert_note_button (1);
1029
1030                 /* when beginning a drag */
1031 #ifdef __APPLE__
1032                 Keyboard::set_copy_modifier (Keyboard::SecondaryModifier);
1033 #else
1034                 Keyboard::set_copy_modifier (Keyboard::PrimaryModifier);
1035 #endif
1036
1037 #ifdef __APPLE__
1038                 ArdourKeyboard::set_constraint_modifier (Keyboard::PrimaryModifier);
1039 #else
1040                 ArdourKeyboard::set_constraint_modifier (Keyboard::TertiaryModifier);
1041 #endif
1042                 ArdourKeyboard::set_push_points_modifier (Keyboard::PrimaryModifier | Keyboard::Level4Modifier);
1043
1044                 /* when beginning a trim */
1045                 ArdourKeyboard::set_trim_contents_modifier (Keyboard::PrimaryModifier);
1046                 ArdourKeyboard::set_trim_anchored_modifier (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier);
1047                 ArdourKeyboard::set_note_size_relative_modifier (Keyboard::TertiaryModifier); // XXX better: 2ndary
1048
1049                 /* while dragging */
1050 #ifdef __APPLE__
1051                 Keyboard::set_snap_modifier (Keyboard::TertiaryModifier);
1052 #else
1053                 Keyboard::set_snap_modifier (Keyboard::SecondaryModifier);
1054 #endif
1055 #ifdef __APPLE__
1056                 Keyboard::set_snap_delta_modifier (Keyboard::Level4Modifier);
1057 #else
1058                 Keyboard::set_snap_delta_modifier (Keyboard::SecondaryModifier | Keyboard::Level4Modifier);
1059 #endif
1060
1061                 /* while trimming */
1062                 ArdourKeyboard::set_trim_overlap_modifier (Keyboard::TertiaryModifier);
1063
1064                 /* while dragging ctrl points */
1065                 ArdourKeyboard::set_fine_adjust_modifier (/*Keyboard::PrimaryModifier | */Keyboard::SecondaryModifier); // XXX
1066
1067                 set_state_from_config ();
1068         }
1069
1070         ComboBoxText _keyboard_layout_selector;
1071         ComboBoxText _edit_modifier_combo;
1072         ComboBoxText _delete_modifier_combo;
1073         ComboBoxText _copy_modifier_combo;
1074         ComboBoxText _insert_note_modifier_combo;
1075         ComboBoxText _snap_modifier_combo;
1076         ComboBoxText _snap_delta_combo;
1077         ComboBoxText _constraint_modifier_combo;
1078         ComboBoxText _trim_contents_combo;
1079         ComboBoxText _trim_overlap_combo;
1080         ComboBoxText _trim_anchored_combo;
1081         ComboBoxText _trim_jump_combo;
1082         ComboBoxText _fine_adjust_combo;
1083         ComboBoxText _push_points_combo;
1084         ComboBoxText _note_size_relative_combo;
1085         Adjustment _delete_button_adjustment;
1086         SpinButton _delete_button_spin;
1087         Adjustment _edit_button_adjustment;
1088         SpinButton _edit_button_spin;
1089         Adjustment _insert_note_button_adjustment;
1090         SpinButton _insert_note_button_spin;
1091
1092 };
1093
1094 class FontScalingOptions : public HSliderOption
1095 {
1096         public:
1097                 FontScalingOptions ()
1098                         : HSliderOption ("font-scale", _("GUI and Font scaling"),
1099                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_font_scale),
1100                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_font_scale),
1101                                         50, 250, 1, 5,
1102                                         1024, false)
1103         {
1104                 const std::string dflt = _("100%");
1105                 const std::string empty = X_(""); // despite gtk-doc saying so, NULL does not work as reference
1106
1107                 _hscale.set_name("FontScaleSlider");
1108                 _hscale.set_draw_value(false);
1109                 _hscale.add_mark(50,  Gtk::POS_TOP, empty);
1110                 _hscale.add_mark(60,  Gtk::POS_TOP, empty);
1111                 _hscale.add_mark(70,  Gtk::POS_TOP, empty);
1112                 _hscale.add_mark(80,  Gtk::POS_TOP, empty);
1113                 _hscale.add_mark(90,  Gtk::POS_TOP, empty);
1114                 _hscale.add_mark(100, Gtk::POS_TOP, dflt);
1115                 _hscale.add_mark(125, Gtk::POS_TOP, empty);
1116                 _hscale.add_mark(150, Gtk::POS_TOP, empty);
1117                 _hscale.add_mark(175, Gtk::POS_TOP, empty);
1118                 _hscale.add_mark(200, Gtk::POS_TOP, empty);
1119                 _hscale.add_mark(250, Gtk::POS_TOP, empty);
1120
1121                 set_note (_("Adjusting the scale requires an application restart to re-layout."));
1122         }
1123
1124         void changed ()
1125         {
1126                 HSliderOption::changed ();
1127                 /* XXX: should be triggered from the parameter changed signal */
1128                 UIConfiguration::instance().reset_dpi ();
1129         }
1130 };
1131
1132 class VstTimeOutSliderOption : public HSliderOption
1133 {
1134 public:
1135         VstTimeOutSliderOption (RCConfiguration* c)
1136                 : HSliderOption ("vst-scan-timeout", _("Scan Time Out"),
1137                                 sigc::mem_fun (*c, &RCConfiguration::get_vst_scan_timeout),
1138                                 sigc::mem_fun (*c, &RCConfiguration::set_vst_scan_timeout),
1139                                 0, 3000, 50, 50)
1140         {
1141                 _label.set_alignment (1.0, 0.5); // match buttons below
1142                 _hscale.set_digits (0);
1143                 _hscale.set_draw_value(false);
1144                 _hscale.add_mark(   0,  Gtk::POS_TOP, _("\u221e")); // infinity
1145                 _hscale.add_mark( 300,  Gtk::POS_TOP, _("30 sec"));
1146                 _hscale.add_mark( 600,  Gtk::POS_TOP, _("1 min"));
1147                 _hscale.add_mark(1200,  Gtk::POS_TOP, _("2 mins"));
1148                 _hscale.add_mark(1800,  Gtk::POS_TOP, _("3 mins"));
1149                 _hscale.add_mark(2400,  Gtk::POS_TOP, _("4 mins"));
1150                 _hscale.add_mark(3000,  Gtk::POS_TOP, _("5 mins"));
1151
1152                 Gtkmm2ext::UI::instance()->set_tip(_hscale,
1153                          _("Specify the default timeout for plugin instantiation. Plugins that require more time to load will be blacklisted. A value of 0 disables the timeout."));
1154         }
1155 };
1156
1157 class ClipLevelOptions : public OptionEditorComponent
1158 {
1159 public:
1160         ClipLevelOptions ()
1161                 : _clip_level_adjustment (-.5, -50.0, 0.0, 0.1, 1.0) /* units of dB */
1162                 , _clip_level_slider (_clip_level_adjustment)
1163                 , _label (_("Waveform Clip Level (dBFS):"))
1164         {
1165                 _label.set_name ("OptionsLabel");
1166
1167                 _clip_level_adjustment.set_value (UIConfiguration::instance().get_waveform_clip_level ());
1168
1169                 _clip_level_slider.set_update_policy (UPDATE_DISCONTINUOUS);
1170
1171                 _clip_level_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &ClipLevelOptions::clip_level_changed));
1172         }
1173
1174         void parameter_changed (string const & p)
1175         {
1176                 if (p == "waveform-clip-level") {
1177                         _clip_level_adjustment.set_value (UIConfiguration::instance().get_waveform_clip_level());
1178                 }
1179                 if (p == "show-waveform-clipping") {
1180                         _clip_level_slider.set_sensitive (UIConfiguration::instance().get_show_waveform_clipping ());
1181                 }
1182         }
1183
1184         void set_state_from_config ()
1185         {
1186                 parameter_changed ("waveform-clip-level");
1187                 parameter_changed ("show-waveform-clipping");
1188         }
1189
1190         void add_to_page (OptionEditorPage* p) {
1191                 add_widgets_to_page (p, &_label, &_clip_level_slider);
1192         }
1193
1194         Gtk::Widget& tip_widget() {
1195                 return _clip_level_slider;
1196         }
1197
1198 private:
1199
1200         void clip_level_changed ()
1201         {
1202                 UIConfiguration::instance().set_waveform_clip_level (_clip_level_adjustment.get_value());
1203                 /* XXX: should be triggered from the parameter changed signal */
1204                 ArdourWaveView::WaveView::set_clip_level (_clip_level_adjustment.get_value());
1205         }
1206
1207         Adjustment _clip_level_adjustment;
1208         HScale _clip_level_slider;
1209         Label _label;
1210 };
1211
1212 class BufferingOptions : public OptionEditorComponent
1213 {
1214         public:
1215                 BufferingOptions (RCConfiguration* c)
1216                         : _rc_config (c)
1217                         , _label (_("Preset:"))
1218                         , _playback ("playback-buffer-seconds", _("Playback (seconds of buffering)"),
1219                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_audio_playback_buffer_seconds),
1220                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_audio_playback_buffer_seconds),
1221                                         1, 60, 1, 4)
1222                         , _capture ("capture-buffer-seconds", _("Recording (seconds of buffering)"),
1223                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_audio_capture_buffer_seconds),
1224                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_audio_capture_buffer_seconds),
1225                                         1, 60, 1, 4)
1226                 {
1227                         // TODO use  ComboOption
1228                         vector<string> presets;
1229
1230                         /* these must match the order of the enums for BufferingPreset */
1231                         presets.push_back (_("Small sessions (4-16 tracks)"));
1232                         presets.push_back (_("Medium sessions (16-64 tracks)"));
1233                         presets.push_back (_("Large sessions (64+ tracks)"));
1234                         presets.push_back (_("Custom (set by sliders below)"));
1235
1236                         set_popdown_strings (_buffering_presets_combo, presets);
1237                         _buffering_presets_combo.signal_changed().connect (sigc::mem_fun (*this, &BufferingOptions::preset_changed));
1238
1239                         _label.set_name ("OptionsLabel");
1240                         _label.set_alignment (0, 0.5);
1241                 }
1242
1243                 void
1244                 add_to_page (OptionEditorPage* p)
1245                 {
1246                         add_widgets_to_page (p, &_label, &_buffering_presets_combo);
1247                         _playback.add_to_page (p);
1248                         _capture.add_to_page (p);
1249                 }
1250
1251                 void parameter_changed (string const & p)
1252                 {
1253                         if (p == "buffering-preset") {
1254                                 switch (_rc_config->get_buffering_preset()) {
1255                                         case Small:
1256                                                 _playback.set_sensitive (false);
1257                                                 _capture.set_sensitive (false);
1258                                                 _buffering_presets_combo.set_active (0);
1259                                                 break;
1260                                         case Medium:
1261                                                 _playback.set_sensitive (false);
1262                                                 _capture.set_sensitive (false);
1263                                                 _buffering_presets_combo.set_active (1);
1264                                                 break;
1265                                         case Large:
1266                                                 _playback.set_sensitive (false);
1267                                                 _capture.set_sensitive (false);
1268                                                 _buffering_presets_combo.set_active (2);
1269                                                 break;
1270                                         case Custom:
1271                                                 _playback.set_sensitive (true);
1272                                                 _capture.set_sensitive (true);
1273                                                 _buffering_presets_combo.set_active (3);
1274                                                 break;
1275                                 }
1276                         }
1277                         _playback.parameter_changed (p);
1278                         _capture.parameter_changed (p);
1279                 }
1280
1281                 void set_state_from_config ()
1282                 {
1283                         parameter_changed ("buffering-preset");
1284                         _playback.set_state_from_config();
1285                         _capture.set_state_from_config();
1286                 }
1287
1288                 Gtk::Widget& tip_widget() { return _buffering_presets_combo; }
1289
1290         private:
1291
1292                 void preset_changed ()
1293                 {
1294                         int index = _buffering_presets_combo.get_active_row_number ();
1295                         if (index < 0) {
1296                                 return;
1297                         }
1298                         switch (index) {
1299                                 case 0:
1300                                         _rc_config->set_buffering_preset (Small);
1301                                         break;
1302                                 case 1:
1303                                         _rc_config->set_buffering_preset (Medium);
1304                                         break;
1305                                 case 2:
1306                                         _rc_config->set_buffering_preset (Large);
1307                                         break;
1308                                 case 3:
1309                                         _rc_config->set_buffering_preset (Custom);
1310                                         break;
1311                                 default:
1312                                         error << string_compose (_("programming error: unknown buffering preset string, index = %1"), index) << endmsg;
1313                                         break;
1314                         }
1315                 }
1316
1317                 RCConfiguration* _rc_config;
1318                 Label         _label;
1319                 HSliderOption _playback;
1320                 HSliderOption _capture;
1321                 ComboBoxText  _buffering_presets_combo;
1322 };
1323
1324 class ControlSurfacesOptions : public OptionEditorMiniPage
1325 {
1326         public:
1327                 ControlSurfacesOptions ()
1328                         : _ignore_view_change (0)
1329                 {
1330                         _store = ListStore::create (_model);
1331                         _view.set_model (_store);
1332                         _view.append_column (_("Control Surface Protocol"), _model.name);
1333                         _view.get_column(0)->set_resizable (true);
1334                         _view.get_column(0)->set_expand (true);
1335                         _view.append_column_editable (_("Enable"), _model.enabled);
1336
1337                         Gtk::HBox* edit_box = manage (new Gtk::HBox);
1338                         edit_box->set_spacing(3);
1339                         edit_box->show ();
1340
1341                         Label* label = manage (new Label);
1342                         label->set_text (_("Edit the settings for selected protocol (it must be ENABLED first):"));
1343                         edit_box->pack_start (*label, false, false);
1344                         label->show ();
1345
1346                         edit_button = manage (new Button(_("Show Protocol Settings")));
1347                         edit_button->signal_clicked().connect (sigc::mem_fun(*this, &ControlSurfacesOptions::edit_btn_clicked));
1348                         edit_box->pack_start (*edit_button, true, true);
1349                         edit_button->set_sensitive (false);
1350                         edit_button->show ();
1351
1352                         int const n = table.property_n_rows();
1353                         table.resize (n + 2, 3);
1354                         table.attach (_view, 0, 3, n, n + 1);
1355                         table.attach (*edit_box, 0, 3, n + 1, n + 2);
1356
1357                         ControlProtocolManager& m = ControlProtocolManager::instance ();
1358                         m.ProtocolStatusChange.connect (protocol_status_connection, MISSING_INVALIDATOR,
1359                                         boost::bind (&ControlSurfacesOptions::protocol_status_changed, this, _1), gui_context());
1360
1361                         _store->signal_row_changed().connect (sigc::mem_fun (*this, &ControlSurfacesOptions::view_changed));
1362                         _view.signal_button_press_event().connect_notify (sigc::mem_fun(*this, &ControlSurfacesOptions::edit_clicked));
1363                         _view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &ControlSurfacesOptions::selection_changed));
1364                 }
1365
1366                 void parameter_changed (std::string const &)
1367                 {
1368
1369                 }
1370
1371                 void set_state_from_config ()
1372                 {
1373                         _store->clear ();
1374
1375                         ControlProtocolManager& m = ControlProtocolManager::instance ();
1376                         for (list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
1377
1378                                 if (!(*i)->mandatory) {
1379                                         TreeModel::Row r = *_store->append ();
1380                                         r[_model.name] = (*i)->name;
1381                                         r[_model.enabled] = 0 != (*i)->protocol;
1382                                         r[_model.protocol_info] = *i;
1383                                 }
1384                         }
1385                 }
1386
1387         private:
1388
1389                 void protocol_status_changed (ControlProtocolInfo* cpi) {
1390                         /* find the row */
1391                         TreeModel::Children rows = _store->children();
1392
1393                         for (TreeModel::Children::iterator x = rows.begin(); x != rows.end(); ++x) {
1394                                 string n = ((*x)[_model.name]);
1395
1396                                 if ((*x)[_model.protocol_info] == cpi) {
1397                                         _ignore_view_change++;
1398                                         (*x)[_model.enabled] = 0 != cpi->protocol;
1399                                         _ignore_view_change--;
1400                                         selection_changed (); // update sensitivity
1401                                         break;
1402                                 }
1403                         }
1404                 }
1405
1406                 void selection_changed ()
1407                 {
1408                         //enable the Edit button when a row is selected for editing
1409                         TreeModel::Row row = *(_view.get_selection()->get_selected());
1410                         if (row && row[_model.enabled]) {
1411                                 ControlProtocolInfo* cpi = row[_model.protocol_info];
1412                                 edit_button->set_sensitive (cpi && cpi->protocol && cpi->protocol->has_editor ());
1413                         } else {
1414                                 edit_button->set_sensitive (false);
1415                         }
1416                 }
1417
1418                 void view_changed (TreeModel::Path const &, TreeModel::iterator const & i)
1419                 {
1420                         TreeModel::Row r = *i;
1421
1422                         if (_ignore_view_change) {
1423                                 return;
1424                         }
1425
1426                         ControlProtocolInfo* cpi = r[_model.protocol_info];
1427                         if (!cpi) {
1428                                 return;
1429                         }
1430
1431                         bool const was_enabled = (cpi->protocol != 0);
1432                         bool const is_enabled = r[_model.enabled];
1433
1434
1435                         if (was_enabled != is_enabled) {
1436
1437                                 if (!was_enabled) {
1438                                         ControlProtocolManager::instance().activate (*cpi);
1439                                 } else {
1440                                         ControlProtocolManager::instance().deactivate (*cpi);
1441                                 }
1442                         }
1443
1444                         selection_changed ();
1445                 }
1446
1447                 void edit_btn_clicked ()
1448                 {
1449                         std::string name;
1450                         ControlProtocolInfo* cpi;
1451                         TreeModel::Row row;
1452
1453                         row = *(_view.get_selection()->get_selected());
1454                         if (!row[_model.enabled]) {
1455                                 return;
1456                         }
1457                         cpi = row[_model.protocol_info];
1458                         if (!cpi || !cpi->protocol || !cpi->protocol->has_editor ()) {
1459                                 return;
1460                         }
1461                         Box* box = (Box*) cpi->protocol->get_gui ();
1462                         if (!box) {
1463                                 return;
1464                         }
1465                         if (box->get_parent()) {
1466                                 static_cast<ArdourWindow*>(box->get_parent())->present();
1467                                 return;
1468                         }
1469                         WindowTitle title (Glib::get_application_name());
1470                         title += row[_model.name];
1471                         title += _("Configuration");
1472                         /* once created, the window is managed by the surface itself (as ->get_parent())
1473                          * Surface's tear_down_gui() is called on session close, when de-activating
1474                          * or re-initializing a surface.
1475                          * tear_down_gui() hides an deletes the Window if it exists.
1476                          */
1477                         ArdourWindow* win = new ArdourWindow (*((Gtk::Window*) _view.get_toplevel()), title.get_string());
1478                         win->set_title (_("Control Protocol Settings"));
1479                         win->add (*box);
1480                         box->show ();
1481                         win->present ();
1482                 }
1483
1484                 void edit_clicked (GdkEventButton* ev)
1485                 {
1486                         if (ev->type != GDK_2BUTTON_PRESS) {
1487                                 return;
1488                         }
1489
1490                         edit_btn_clicked();
1491                 }
1492
1493                 class ControlSurfacesModelColumns : public TreeModelColumnRecord
1494         {
1495                 public:
1496
1497                         ControlSurfacesModelColumns ()
1498                         {
1499                                 add (name);
1500                                 add (enabled);
1501                                 add (protocol_info);
1502                         }
1503
1504                         TreeModelColumn<string> name;
1505                         TreeModelColumn<bool> enabled;
1506                         TreeModelColumn<ControlProtocolInfo*> protocol_info;
1507         };
1508
1509                 Glib::RefPtr<ListStore> _store;
1510                 ControlSurfacesModelColumns _model;
1511                 TreeView _view;
1512                 PBD::ScopedConnection protocol_status_connection;
1513                 uint32_t _ignore_view_change;
1514                 Gtk::Button* edit_button;
1515 };
1516
1517 class VideoTimelineOptions : public OptionEditorMiniPage
1518 {
1519         public:
1520                 VideoTimelineOptions (RCConfiguration* c)
1521                         : _rc_config (c)
1522                         , _show_video_export_info_button (_("Show Video Export Info before export"))
1523                         , _show_video_server_dialog_button (_("Show Video Server Startup Dialog"))
1524                         , _video_advanced_setup_button (_("Advanced Setup (remote video server)"))
1525                         , _xjadeo_browse_button (_("Browse..."))
1526                 {
1527                         Table* t = &table;
1528                         int n = table.property_n_rows();
1529
1530                         t->attach (_show_video_export_info_button, 1, 4, n, n + 1);
1531                         _show_video_export_info_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::show_video_export_info_toggled));
1532                         Gtkmm2ext::UI::instance()->set_tip (_show_video_export_info_button,
1533                                         _("<b>When enabled</b> an information window with details is displayed before the video-export dialog."));
1534                         ++n;
1535
1536                         t->attach (_show_video_server_dialog_button, 1, 4, n, n + 1);
1537                         _show_video_server_dialog_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::show_video_server_dialog_toggled));
1538                         Gtkmm2ext::UI::instance()->set_tip (_show_video_server_dialog_button,
1539                                         _("<b>When enabled</b> the video server is never launched automatically without confirmation"));
1540                         ++n;
1541
1542                         t->attach (_video_advanced_setup_button, 1, 4, n, n + 1, FILL);
1543                         _video_advanced_setup_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::video_advanced_setup_toggled));
1544                         Gtkmm2ext::UI::instance()->set_tip (_video_advanced_setup_button,
1545                                         _("<b>When enabled</b> you can specify a custom video-server URL and docroot. - Do not enable this option unless you know what you are doing."));
1546                         ++n;
1547
1548                         Label* l = manage (new Label (_("Video Server URL:")));
1549                         l->set_alignment (0, 0.5);
1550                         t->attach (*l, 1, 2, n, n + 1, FILL);
1551                         t->attach (_video_server_url_entry, 2, 4, n, n + 1, FILL);
1552                         Gtkmm2ext::UI::instance()->set_tip (_video_server_url_entry,
1553                                         _("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"));
1554                         ++n;
1555
1556                         l = manage (new Label (_("Video Folder:")));
1557                         l->set_alignment (0, 0.5);
1558                         t->attach (*l, 1, 2, n, n + 1, FILL);
1559                         t->attach (_video_server_docroot_entry, 2, 4, n, n + 1);
1560                         Gtkmm2ext::UI::instance()->set_tip (_video_server_docroot_entry,
1561                                         _("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 unavailable. It is used for the local video-monitor and file-browsing when opening/adding a video file."));
1562                         ++n;
1563
1564                         l = manage (new Label (""));
1565                         t->attach (*l, 0, 4, n, n + 1, EXPAND | FILL);
1566                         ++n;
1567
1568                         l = manage (new Label (string_compose ("<b>%1</b>", _("Video Monitor"))));
1569                         l->set_use_markup (true);
1570                         l->set_alignment (0, 0.5);
1571                         t->attach (*l, 0, 4, n, n + 1, EXPAND | FILL);
1572                         ++n;
1573
1574                         l = manage (new Label (string_compose (_("Custom Path to Video Monitor (%1) - leave empty for default:"),
1575 #ifdef __APPLE__
1576                                                         "Jadeo.app"
1577 #elif defined PLATFORM_WINDOWS
1578                                                         "xjadeo.exe"
1579 #else
1580                                                         "xjadeo"
1581 #endif
1582                                                         )));
1583                         l->set_alignment (0, 0.5);
1584                         t->attach (*l, 1, 4, n, n + 1, FILL);
1585                         ++n;
1586
1587                         t->attach (_custom_xjadeo_path, 2, 3, n, n + 1, EXPAND|FILL);
1588                         Gtkmm2ext::UI::instance()->set_tip (_custom_xjadeo_path, _("Set a custom path to the Video Monitor Executable, changing this requires a restart."));
1589                         t->attach (_xjadeo_browse_button, 3, 4, n, n + 1, FILL);
1590
1591                         _video_server_url_entry.signal_changed().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_url_changed));
1592                         _video_server_url_entry.signal_activate().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_url_changed));
1593                         _video_server_docroot_entry.signal_changed().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_docroot_changed));
1594                         _video_server_docroot_entry.signal_activate().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_docroot_changed));
1595                         _custom_xjadeo_path.signal_changed().connect (sigc::mem_fun (*this, &VideoTimelineOptions::custom_xjadeo_path_changed));
1596                         _xjadeo_browse_button.signal_clicked ().connect (sigc::mem_fun (*this, &VideoTimelineOptions::xjadeo_browse_clicked));
1597
1598                         // xjadeo-path is a UIConfig parameter
1599                         UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &VideoTimelineOptions::parameter_changed));
1600                 }
1601
1602                 void server_url_changed ()
1603                 {
1604                         _rc_config->set_video_server_url (_video_server_url_entry.get_text());
1605                 }
1606
1607                 void server_docroot_changed ()
1608                 {
1609                         _rc_config->set_video_server_docroot (_video_server_docroot_entry.get_text());
1610                 }
1611
1612                 void show_video_export_info_toggled ()
1613                 {
1614                         bool const x = _show_video_export_info_button.get_active ();
1615                         _rc_config->set_show_video_export_info (x);
1616                 }
1617
1618                 void show_video_server_dialog_toggled ()
1619                 {
1620                         bool const x = _show_video_server_dialog_button.get_active ();
1621                         _rc_config->set_show_video_server_dialog (x);
1622                 }
1623
1624                 void video_advanced_setup_toggled ()
1625                 {
1626                         bool const x = _video_advanced_setup_button.get_active ();
1627                         _rc_config->set_video_advanced_setup(x);
1628                 }
1629
1630                 void custom_xjadeo_path_changed ()
1631                 {
1632                         UIConfiguration::instance().set_xjadeo_binary (_custom_xjadeo_path.get_text());
1633                 }
1634
1635                 void xjadeo_browse_clicked ()
1636                 {
1637                         Gtk::FileChooserDialog dialog(_("Set Video Monitor Executable"), Gtk::FILE_CHOOSER_ACTION_OPEN);
1638                         dialog.set_filename (UIConfiguration::instance().get_xjadeo_binary());
1639                         dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1640                         dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
1641                         if (dialog.run () == Gtk::RESPONSE_OK) {
1642                                 const std::string& filename = dialog.get_filename();
1643                                 if (!filename.empty() && (
1644 #ifdef __APPLE__
1645                                                         Glib::file_test (filename + "/Contents/MacOS/xjadeo", Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE) ||
1646 #endif
1647                                                         Glib::file_test (filename, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)
1648                                                         )) {
1649                                         UIConfiguration::instance().set_xjadeo_binary (filename);
1650                                 }
1651                         }
1652                 }
1653
1654                 void parameter_changed (string const & p)
1655                 {
1656                         if (p == "video-server-url") {
1657                                 _video_server_url_entry.set_text (_rc_config->get_video_server_url());
1658                         } else if (p == "video-server-docroot") {
1659                                 _video_server_docroot_entry.set_text (_rc_config->get_video_server_docroot());
1660                         } else if (p == "show-video-export-info") {
1661                                 bool const x = _rc_config->get_show_video_export_info();
1662                                 _show_video_export_info_button.set_active (x);
1663                         } else if (p == "show-video-server-dialog") {
1664                                 bool const x = _rc_config->get_show_video_server_dialog();
1665                                 _show_video_server_dialog_button.set_active (x);
1666                         } else if (p == "video-advanced-setup") {
1667                                 bool const x = _rc_config->get_video_advanced_setup();
1668                                 _video_advanced_setup_button.set_active(x);
1669                                 _video_server_docroot_entry.set_sensitive(x);
1670                                 _video_server_url_entry.set_sensitive(x);
1671                         } else if (p == "xjadeo-binary") {
1672                                 _custom_xjadeo_path.set_text (UIConfiguration::instance().get_xjadeo_binary());
1673                         }
1674                 }
1675
1676                 void set_state_from_config ()
1677                 {
1678                         parameter_changed ("video-server-url");
1679                         parameter_changed ("video-server-docroot");
1680                         parameter_changed ("video-monitor-setup-dialog");
1681                         parameter_changed ("show-video-export-info");
1682                         parameter_changed ("show-video-server-dialog");
1683                         parameter_changed ("video-advanced-setup");
1684                         parameter_changed ("xjadeo-binary");
1685                 }
1686
1687         private:
1688                 RCConfiguration* _rc_config;
1689                 Entry _video_server_url_entry;
1690                 Entry _video_server_docroot_entry;
1691                 Entry _custom_xjadeo_path;
1692                 CheckButton _show_video_export_info_button;
1693                 CheckButton _show_video_server_dialog_button;
1694                 CheckButton _video_advanced_setup_button;
1695                 Button _xjadeo_browse_button;
1696 };
1697
1698 class ColumVisibilityOption : public Option
1699 {
1700         public:
1701         ColumVisibilityOption (string id, string name, uint32_t n_col, sigc::slot<uint32_t> get, sigc::slot<bool, uint32_t> set)
1702                 : Option (id, name)
1703                 , _heading (name)
1704                 , _n_col (n_col)
1705                 , _get (get)
1706                 , _set (set)
1707         {
1708                 cb = (CheckButton**) malloc (sizeof (CheckButton*) * n_col);
1709                 for (uint32_t i = 0; i < n_col; ++i) {
1710                         CheckButton* col = manage (new CheckButton (string_compose (_("Column %1"), i + 1)));
1711                         col->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &ColumVisibilityOption::column_toggled), i));
1712                         _hbox.pack_start (*col);
1713                         cb[i] = col;
1714                 }
1715                 parameter_changed (id);
1716         }
1717
1718         ~ColumVisibilityOption () {
1719                 free (cb);
1720         }
1721
1722         Gtk::Widget& tip_widget() { return _hbox; }
1723
1724         void set_state_from_config ()
1725         {
1726                 uint32_t c = _get();
1727                 for (uint32_t i = 0; i < _n_col; ++i) {
1728                         bool en = (c & (1<<i)) ? true : false;
1729                         if (cb[i]->get_active () != en) {
1730                                 cb[i]->set_active (en);
1731                         }
1732                 }
1733         }
1734
1735         void add_to_page (OptionEditorPage* p)
1736         {
1737                 _heading.add_to_page (p);
1738                 add_widget_to_page (p, &_hbox);
1739         }
1740         private:
1741
1742         void column_toggled (int b) {
1743                 uint32_t c = _get();
1744                 uint32_t cc = c;
1745                 if (cb[b]->get_active ()) {
1746                         c |= (1<<b);
1747                 } else {
1748                         c &= ~(1<<b);
1749                 }
1750                 if (cc != c) {
1751                         _set (c);
1752                 }
1753         }
1754
1755         HBox _hbox;
1756         OptionEditorHeading _heading;
1757
1758         CheckButton** cb;
1759         uint32_t _n_col;
1760         sigc::slot<uint32_t> _get;
1761         sigc::slot<bool, uint32_t> _set;
1762 };
1763
1764
1765 /** A class which allows control of visibility of some editor components usign
1766  *  a VisibilityGroup.  The caller should pass in a `dummy' VisibilityGroup
1767  *  which has the correct members, but with null widget pointers.  This
1768  *  class allows the user to set visibility of the members, the details
1769  *  of which are stored in a configuration variable which can be watched
1770  *  by parts of the editor that actually contain the widgets whose visibility
1771  *  is being controlled.
1772  */
1773
1774 class VisibilityOption : public Option
1775 {
1776 public:
1777         /** @param name User-visible name for this group.
1778          *  @param g `Dummy' VisibilityGroup (as described above).
1779          *  @param get Method to get the value of the appropriate configuration variable.
1780          *  @param set Method to set the value of the appropriate configuration variable.
1781          */
1782         VisibilityOption (string name, VisibilityGroup* g, sigc::slot<string> get, sigc::slot<bool, string> set)
1783                 : Option (g->get_state_name(), name)
1784                 , _heading (name)
1785                 , _visibility_group (g)
1786                 , _get (get)
1787                 , _set (set)
1788         {
1789                 /* Watch for changes made by the user to our members */
1790                 _visibility_group->VisibilityChanged.connect_same_thread (
1791                         _visibility_group_connection, sigc::bind (&VisibilityOption::changed, this)
1792                         );
1793         }
1794
1795         void set_state_from_config ()
1796         {
1797                 /* Set our state from the current configuration */
1798                 _visibility_group->set_state (_get ());
1799         }
1800
1801         void add_to_page (OptionEditorPage* p)
1802         {
1803                 _heading.add_to_page (p);
1804                 add_widget_to_page (p, _visibility_group->list_view ());
1805         }
1806
1807         Gtk::Widget& tip_widget() { return *_visibility_group->list_view (); }
1808
1809 private:
1810         void changed ()
1811         {
1812                 /* The user has changed something, so reflect this change
1813                    in the RCConfiguration.
1814                 */
1815                 _set (_visibility_group->get_state_value ());
1816         }
1817
1818         OptionEditorHeading _heading;
1819         VisibilityGroup* _visibility_group;
1820         sigc::slot<std::string> _get;
1821         sigc::slot<bool, std::string> _set;
1822         PBD::ScopedConnection _visibility_group_connection;
1823 };
1824
1825
1826 class MidiPortOptions : public OptionEditorMiniPage, public sigc::trackable
1827 {
1828         public:
1829                 MidiPortOptions() {
1830
1831                         setup_midi_port_view (midi_output_view, false);
1832                         setup_midi_port_view (midi_input_view, true);
1833
1834                         OptionEditorHeading* h = new OptionEditorHeading (_("MIDI Inputs"));
1835                         h->add_to_page (this);
1836
1837                         Gtk::ScrolledWindow* scroller = manage (new Gtk::ScrolledWindow);
1838                         scroller->add (midi_input_view);
1839                         scroller->set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
1840                         scroller->set_size_request (-1, 180);
1841
1842                         int n = table.property_n_rows();
1843                         table.attach (*scroller, 0, 3, n, n + 1, FILL | EXPAND);
1844
1845                         h = new OptionEditorHeading (_("MIDI Outputs"));
1846                         h->add_to_page (this);
1847
1848                         scroller = manage (new Gtk::ScrolledWindow);
1849                         scroller->add (midi_output_view);
1850                         scroller->set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
1851                         scroller->set_size_request (-1, 180);
1852
1853                         n = table.property_n_rows();
1854                         table.attach (*scroller, 0, 3, n, n + 1, FILL | EXPAND);
1855
1856                         midi_output_view.show ();
1857                         midi_input_view.show ();
1858
1859                         table.signal_show().connect (sigc::mem_fun (*this, &MidiPortOptions::on_show));
1860                 }
1861
1862                 void parameter_changed (string const&) {}
1863                 void set_state_from_config() {}
1864
1865                 void on_show () {
1866                         refill ();
1867
1868                         AudioEngine::instance()->PortRegisteredOrUnregistered.connect (connections,
1869                                         invalidator (*this),
1870                                         boost::bind (&MidiPortOptions::refill, this),
1871                                         gui_context());
1872                         AudioEngine::instance()->MidiPortInfoChanged.connect (connections,
1873                                         invalidator (*this),
1874                                         boost::bind (&MidiPortOptions::refill, this),
1875                                         gui_context());
1876                         AudioEngine::instance()->MidiSelectionPortsChanged.connect (connections,
1877                                         invalidator (*this),
1878                                         boost::bind (&MidiPortOptions::refill, this),
1879                                         gui_context());
1880                 }
1881
1882                 void refill () {
1883
1884                         if (refill_midi_ports (true, midi_input_view)) {
1885                                 input_label.show ();
1886                         } else {
1887                                 input_label.hide ();
1888                         }
1889                         if (refill_midi_ports (false, midi_output_view)) {
1890                                 output_label.show ();
1891                         } else {
1892                                 output_label.hide ();
1893                         }
1894                 }
1895
1896         private:
1897                 PBD::ScopedConnectionList connections;
1898
1899                 /* MIDI port management */
1900                 struct MidiPortColumns : public Gtk::TreeModel::ColumnRecord {
1901
1902                         MidiPortColumns () {
1903                                 add (pretty_name);
1904                                 add (music_data);
1905                                 add (control_data);
1906                                 add (selection);
1907                                 add (name);
1908                                 add (filler);
1909                         }
1910
1911                         Gtk::TreeModelColumn<std::string> pretty_name;
1912                         Gtk::TreeModelColumn<bool> music_data;
1913                         Gtk::TreeModelColumn<bool> control_data;
1914                         Gtk::TreeModelColumn<bool> selection;
1915                         Gtk::TreeModelColumn<std::string> name;
1916                         Gtk::TreeModelColumn<std::string> filler;
1917                 };
1918
1919                 MidiPortColumns midi_port_columns;
1920                 Gtk::TreeView midi_input_view;
1921                 Gtk::TreeView midi_output_view;
1922                 Gtk::Label input_label;
1923                 Gtk::Label output_label;
1924
1925                 void setup_midi_port_view (Gtk::TreeView&, bool with_selection);
1926                 bool refill_midi_ports (bool for_input, Gtk::TreeView&);
1927                 void pretty_name_edit (std::string const & path, std::string const & new_text, Gtk::TreeView*);
1928                 void midi_music_column_toggled (std::string const & path, Gtk::TreeView*);
1929                 void midi_control_column_toggled (std::string const & path, Gtk::TreeView*);
1930                 void midi_selection_column_toggled (std::string const & path, Gtk::TreeView*);
1931 };
1932
1933 void
1934 MidiPortOptions::setup_midi_port_view (Gtk::TreeView& view, bool with_selection)
1935 {
1936         int pretty_name_column;
1937         int music_column;
1938         int control_column;
1939         int selection_column;
1940         TreeViewColumn* col;
1941         Gtk::Label* l;
1942
1943         pretty_name_column = view.append_column_editable (_("Name (click to edit)"), midi_port_columns.pretty_name) - 1;
1944
1945         col = manage (new TreeViewColumn ("", midi_port_columns.music_data));
1946         col->set_alignment (ALIGN_CENTER);
1947         l = manage (new Label (_("Music Data")));
1948         set_tooltip (*l, string_compose (_("If ticked, %1 will consider this port to be a source of music performance data."), PROGRAM_NAME));
1949         col->set_widget (*l);
1950         l->show ();
1951         music_column = view.append_column (*col) - 1;
1952
1953         col = manage (new TreeViewColumn ("", midi_port_columns.control_data));
1954         col->set_alignment (ALIGN_CENTER);
1955         l = manage (new Label (_("Control Data")));
1956         set_tooltip (*l, string_compose (_("If ticked, %1 will consider this port to be a source of control data."), PROGRAM_NAME));
1957         col->set_widget (*l);
1958         l->show ();
1959         control_column = view.append_column (*col) - 1;
1960
1961         if (with_selection) {
1962                 col = manage (new TreeViewColumn (_("Follow Selection"), midi_port_columns.selection));
1963                 selection_column = view.append_column (*col) - 1;
1964                 l = manage (new Label (_("Follow Selection")));
1965                 set_tooltip (*l, string_compose (_("If ticked, and \"MIDI input follows selection\" is enabled,\n%1 will automatically connect the first selected MIDI track to this port.\n"), PROGRAM_NAME));
1966                 col->set_widget (*l);
1967                 l->show ();
1968         }
1969
1970         /* filler column so that the last real column doesn't expand */
1971         view.append_column ("", midi_port_columns.filler);
1972
1973         CellRendererText* pretty_name_cell = dynamic_cast<CellRendererText*> (view.get_column_cell_renderer (pretty_name_column));
1974         pretty_name_cell->property_editable() = true;
1975         pretty_name_cell->signal_edited().connect (sigc::bind (sigc::mem_fun (*this, &MidiPortOptions::pretty_name_edit), &view));
1976
1977         CellRendererToggle* toggle_cell;
1978
1979         toggle_cell = dynamic_cast<CellRendererToggle*> (view.get_column_cell_renderer (music_column));
1980         toggle_cell->property_activatable() = true;
1981         toggle_cell->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiPortOptions::midi_music_column_toggled), &view));
1982
1983         toggle_cell = dynamic_cast<CellRendererToggle*> (view.get_column_cell_renderer (control_column));
1984         toggle_cell->property_activatable() = true;
1985         toggle_cell->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiPortOptions::midi_control_column_toggled), &view));
1986
1987         if (with_selection) {
1988                 toggle_cell = dynamic_cast<CellRendererToggle*> (view.get_column_cell_renderer (selection_column));
1989                 toggle_cell->property_activatable() = true;
1990                 toggle_cell->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiPortOptions::midi_selection_column_toggled), &view));
1991         }
1992
1993         view.get_selection()->set_mode (SELECTION_NONE);
1994         view.set_tooltip_column (4); /* port "real" name */
1995         view.get_column(0)->set_resizable (true);
1996         view.get_column(0)->set_expand (true);
1997 }
1998
1999 bool
2000 MidiPortOptions::refill_midi_ports (bool for_input, Gtk::TreeView& view)
2001 {
2002         using namespace ARDOUR;
2003
2004         std::vector<string> ports;
2005
2006         AudioEngine::instance()->get_known_midi_ports (ports);
2007
2008         if (ports.empty()) {
2009                 view.hide ();
2010                 return false;
2011         }
2012
2013         Glib::RefPtr<ListStore> model = Gtk::ListStore::create (midi_port_columns);
2014
2015         for (vector<string>::const_iterator s = ports.begin(); s != ports.end(); ++s) {
2016
2017                 if (AudioEngine::instance()->port_is_mine (*s)) {
2018                         continue;
2019                 }
2020
2021                 PortManager::MidiPortInformation mpi (AudioEngine::instance()->midi_port_information (*s));
2022
2023                 if (mpi.pretty_name.empty()) {
2024                         /* vanished since get_known_midi_ports() */
2025                         continue;
2026                 }
2027
2028                 if (for_input != mpi.input) {
2029                         continue;
2030                 }
2031
2032                 TreeModel::Row row = *(model->append());
2033
2034                 row[midi_port_columns.pretty_name] = mpi.pretty_name;
2035                 row[midi_port_columns.music_data] = mpi.properties & MidiPortMusic;
2036                 row[midi_port_columns.control_data] = mpi.properties & MidiPortControl;
2037                 row[midi_port_columns.selection] = mpi.properties & MidiPortSelection;
2038                 row[midi_port_columns.name] = *s;
2039         }
2040
2041         view.set_model (model);
2042
2043         return true;
2044 }
2045
2046 void
2047 MidiPortOptions::midi_music_column_toggled (string const & path, TreeView* view)
2048 {
2049         TreeIter iter = view->get_model()->get_iter (path);
2050
2051         if (!iter) {
2052                 return;
2053         }
2054
2055         bool new_value = ! bool ((*iter)[midi_port_columns.music_data]);
2056
2057         /* don't reset model - wait for MidiPortInfoChanged signal */
2058
2059         if (new_value) {
2060                 ARDOUR::AudioEngine::instance()->add_midi_port_flags ((*iter)[midi_port_columns.name], MidiPortMusic);
2061         } else {
2062                 ARDOUR::AudioEngine::instance()->remove_midi_port_flags ((*iter)[midi_port_columns.name], MidiPortMusic);
2063         }
2064 }
2065
2066 void
2067 MidiPortOptions::midi_control_column_toggled (string const & path, TreeView* view)
2068 {
2069         TreeIter iter = view->get_model()->get_iter (path);
2070
2071         if (!iter) {
2072                 return;
2073         }
2074
2075         bool new_value = ! bool ((*iter)[midi_port_columns.control_data]);
2076
2077         /* don't reset model - wait for MidiPortInfoChanged signal */
2078
2079         if (new_value) {
2080                 ARDOUR::AudioEngine::instance()->add_midi_port_flags ((*iter)[midi_port_columns.name], MidiPortControl);
2081         } else {
2082                 ARDOUR::AudioEngine::instance()->remove_midi_port_flags ((*iter)[midi_port_columns.name], MidiPortControl);
2083         }
2084 }
2085
2086 void
2087 MidiPortOptions::midi_selection_column_toggled (string const & path, TreeView* view)
2088 {
2089         TreeIter iter = view->get_model()->get_iter (path);
2090
2091         if (!iter) {
2092                 return;
2093         }
2094
2095         bool new_value = ! bool ((*iter)[midi_port_columns.selection]);
2096
2097         /* don't reset model - wait for MidiSelectionPortsChanged signal */
2098
2099         if (new_value) {
2100                 ARDOUR::AudioEngine::instance()->add_midi_port_flags ((*iter)[midi_port_columns.name], MidiPortSelection);
2101         } else {
2102                 ARDOUR::AudioEngine::instance()->remove_midi_port_flags ((*iter)[midi_port_columns.name], MidiPortSelection);
2103         }
2104 }
2105
2106 void
2107 MidiPortOptions::pretty_name_edit (std::string const & path, string const & new_text, Gtk::TreeView* view)
2108 {
2109         TreeIter iter = view->get_model()->get_iter (path);
2110
2111         if (!iter) {
2112                 return;
2113         }
2114
2115         AudioEngine::instance()->set_midi_port_pretty_name ((*iter)[midi_port_columns.name], new_text);
2116 }
2117
2118 /*============*/
2119
2120
2121 RCOptionEditor::RCOptionEditor ()
2122         : OptionEditorContainer (Config, string_compose (_("%1 Preferences"), PROGRAM_NAME))
2123         , Tabbable (*this, _("Preferences")
2124 #ifdef MIXBUS
2125                         , false // detached by default (first start, no instant.xml)
2126 #endif
2127                         ) /* pack self-as-vbox into tabbable */
2128         , _rc_config (Config)
2129         , _mixer_strip_visibility ("mixer-element-visibility")
2130 {
2131         UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &RCOptionEditor::parameter_changed));
2132
2133         /* MISC */
2134
2135         uint32_t hwcpus = hardware_concurrency ();
2136         BoolOption* bo;
2137
2138         if (hwcpus > 1) {
2139                 add_option (_("General"), new OptionEditorHeading (_("DSP CPU Utilization")));
2140
2141                 ComboOption<int32_t>* procs = new ComboOption<int32_t> (
2142                                 "processor-usage",
2143                                 _("Signal processing uses"),
2144                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_processor_usage),
2145                                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_processor_usage)
2146                                 );
2147
2148                 procs->add (-1, _("all but one processor"));
2149                 procs->add (0, _("all available processors"));
2150
2151                 for (uint32_t i = 1; i <= hwcpus; ++i) {
2152                         procs->add (i, string_compose (P_("%1 processor", "%1 processors", i), i));
2153                 }
2154
2155                 procs->set_note (string_compose (_("This setting will only take effect when %1 is restarted."), PROGRAM_NAME));
2156
2157                 add_option (_("General"), procs);
2158         }
2159
2160         /* Image cache size */
2161         add_option (_("General"), new OptionEditorHeading (_("Memory Usage")));
2162
2163         HSliderOption *sics = new HSliderOption ("waveform-cache-size",
2164                         _("Waveform image cache size (megabytes)"),
2165                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_cache_size),
2166                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_cache_size),
2167                         1, 1024, 10 /* 1 MB to 1GB in steps of 10MB */
2168                         );
2169         sics->scale().set_digits (0);
2170         Gtkmm2ext::UI::instance()->set_tip (
2171                         sics->tip_widget(),
2172                  _("Increasing the cache size uses more memory to store waveform images, which can improve graphical performance."));
2173         add_option (_("General"), sics);
2174
2175         add_option (_("General"), new OptionEditorHeading (_("Engine")));
2176
2177         add_option (_("General"),
2178              new BoolOption (
2179                      "try-autostart-engine",
2180                      _("Try to auto-launch audio/midi engine"),
2181                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_try_autostart_engine),
2182                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_try_autostart_engine)
2183                      ));
2184
2185         add_option (_("General"), new OptionEditorHeading (_("Automation")));
2186
2187         add_option (_("General"),
2188              new SpinOption<double> (
2189                      "automation-thinning-factor",
2190                      _("Thinning factor (larger value => less data)"),
2191                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_thinning_factor),
2192                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_thinning_factor),
2193                      0, 1000, 1, 20
2194                      ));
2195
2196         add_option (_("General"),
2197              new SpinOption<double> (
2198                      "automation-interval-msecs",
2199                      _("Automation sampling interval (milliseconds)"),
2200                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_interval_msecs),
2201                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_interval_msecs),
2202                      1, 1000, 1, 20
2203                      ));
2204
2205         add_option (_("General"), new OptionEditorHeading (_("Tempo")));
2206
2207         bo = new BoolOption (
2208                 "allow-non-quarter-pulse",
2209                 _("Allow non quarter-note pulse"),
2210                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_allow_non_quarter_pulse),
2211                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_allow_non_quarter_pulse)
2212                 );
2213         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2214                                             string_compose (_("<b>When enabled</b> %1 will allow tempo to be expressed in divisions per minute\n"
2215                                                               "<b>When disabled</b> %1 will only allow tempo to be expressed in quarter notes per minute"),
2216                                                             PROGRAM_NAME));
2217         add_option (_("General"), bo);
2218
2219         if (!ARDOUR::Profile->get_mixbus()) {
2220                 add_option (_("General"), new OptionEditorHeading (_("GUI Lock")));
2221                 /* Lock GUI timeout */
2222
2223                 HSliderOption *slts = new HSliderOption("lock-gui-after-seconds",
2224                                 _("Lock timeout (seconds)"),
2225                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_lock_gui_after_seconds),
2226                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_lock_gui_after_seconds),
2227                                 0, 1000, 1, 10
2228                                 );
2229                 slts->scale().set_digits (0);
2230                 Gtkmm2ext::UI::instance()->set_tip (
2231                                 slts->tip_widget(),
2232                                 _("Lock GUI after this many idle seconds (zero to never lock)"));
2233                 add_option (_("General"), slts);
2234         } // !mixbus
2235
2236         add_option (_("General/Session"), new OptionEditorHeading (S_("Options|Undo")));
2237
2238         add_option (_("General/Session"), new UndoOptions (_rc_config));
2239
2240         add_option (_("General/Session"),
2241              new BoolOption (
2242                      "verify-remove-last-capture",
2243                      _("Verify removal of last capture"),
2244                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_verify_remove_last_capture),
2245                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_verify_remove_last_capture)
2246                      ));
2247
2248         add_option (_("General/Session"), new OptionEditorHeading (_("Session Management")));
2249
2250         add_option (_("General/Session"),
2251              new BoolOption (
2252                      "periodic-safety-backups",
2253                      _("Make periodic backups of the session file"),
2254                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_periodic_safety_backups),
2255                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_periodic_safety_backups)
2256                      ));
2257
2258         add_option (_("General/Session"),
2259              new BoolOption (
2260                      "only-copy-imported-files",
2261                      _("Always copy imported files"),
2262                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_only_copy_imported_files),
2263                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_only_copy_imported_files)
2264                      ));
2265
2266         add_option (_("General/Session"), new DirectoryOption (
2267                             X_("default-session-parent-dir"),
2268                             _("Default folder for new sessions:"),
2269                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_default_session_parent_dir),
2270                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_default_session_parent_dir)
2271                             ));
2272
2273         add_option (_("General/Session"),
2274              new SpinOption<uint32_t> (
2275                      "max-recent-sessions",
2276                      _("Maximum number of recent sessions"),
2277                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_max_recent_sessions),
2278                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_max_recent_sessions),
2279                      0, 1000, 1, 20
2280                      ));
2281
2282
2283 #if ENABLE_NLS
2284
2285         add_option (_("General/Translation"), new OptionEditorHeading (_("Internationalization")));
2286
2287         bo = new BoolOption (
2288                         "enable-translation",
2289                         _("Use translations"),
2290                         sigc::ptr_fun (ARDOUR::translations_are_enabled),
2291                         sigc::ptr_fun (ARDOUR::set_translations_enabled)
2292                         );
2293
2294         bo->set_note (string_compose (_("These settings will only take effect after %1 is restarted (if available for your language preferences)."), PROGRAM_NAME));
2295
2296         add_option (_("General/Translation"), bo);
2297
2298         parameter_changed ("enable-translation");
2299 #endif // ENABLE_NLS
2300
2301
2302         /* EDITOR */
2303
2304         add_option (_("Editor"), new OptionEditorHeading (_("General")));
2305
2306         bo = new BoolOption (
2307                      "name-new-markers",
2308                      _("Prompt for new marker names"),
2309                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_name_new_markers),
2310                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_name_new_markers)
2311                 );
2312         add_option (_("Editor"), bo);
2313         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."
2314                                                                 "\n\nYou can always rename markers by right-clicking on them"));
2315
2316         add_option (_("Editor"),
2317              new BoolOption (
2318                      "draggable-playhead",
2319                      _("Allow dragging of playhead"),
2320                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_draggable_playhead),
2321                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_draggable_playhead)
2322                      ));
2323
2324         ComboOption<float>* dps = new ComboOption<float> (
2325                      "draggable-playhead-speed",
2326                      _("Playhead dragging speed (%)"),
2327                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_draggable_playhead_speed),
2328                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_draggable_playhead_speed)
2329                      );
2330         dps->add (0.05, _("5%"));
2331         dps->add (0.1, _("10%"));
2332         dps->add (0.25, _("25%"));
2333         dps->add (0.5, _("50%"));
2334         dps->add (1.0, _("100%"));
2335         add_option (_("Editor"), dps);
2336
2337         ComboOption<float>* eet = new ComboOption<float> (
2338                      "extra-ui-extents-time",
2339                      _("Limit zooming & summary view to X minutes beyond session extents"),
2340                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_extra_ui_extents_time),
2341                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_extra_ui_extents_time)
2342                      );
2343         eet->add (1, _("1 minute"));
2344         eet->add (2, _("2 minutes"));
2345         eet->add (20, _("20 minutes"));
2346         eet->add (60, _("1 hour"));
2347         eet->add (60*2, _("2 hours"));
2348         eet->add (60*24, _("24 hours"));
2349         add_option (_("Editor"), eet);
2350
2351         if (!Profile->get_mixbus()) {
2352
2353                 add_option (_("Editor"),
2354                                 new BoolOption (
2355                                         "use-mouse-position-as-zoom-focus-on-scroll",
2356                                         _("Zoom to mouse position when zooming with scroll wheel"),
2357                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_mouse_position_as_zoom_focus_on_scroll),
2358                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_mouse_position_as_zoom_focus_on_scroll)
2359                                         ));
2360         }  // !mixbus
2361
2362         add_option (_("Editor"),
2363                     new BoolOption (
2364                             "use-time-rulers-to-zoom-with-vertical-drag",
2365                             _("Zoom with vertical drag in rulers"),
2366                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_time_rulers_to_zoom_with_vertical_drag),
2367                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_time_rulers_to_zoom_with_vertical_drag)
2368                             ));
2369
2370         add_option (_("Editor"),
2371                     new BoolOption (
2372                             "use-double-click-to-zoom-to-selection",
2373                             _("Double click zooms to selection"),
2374                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_double_click_to_zoom_to_selection),
2375                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_double_click_to_zoom_to_selection)
2376                             ));
2377
2378         add_option (_("Editor"),
2379                     new BoolOption (
2380                             "update-editor-during-summary-drag",
2381                             _("Update editor window during drags of the summary"),
2382                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_update_editor_during_summary_drag),
2383                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_update_editor_during_summary_drag)
2384                             ));
2385
2386         add_option (_("Editor"),
2387             new BoolOption (
2388                     "autoscroll-editor",
2389                     _("Auto-scroll editor window when dragging near its edges"),
2390                     sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_autoscroll_editor),
2391                     sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_autoscroll_editor)
2392                     ));
2393
2394         add_option (_("Editor"),
2395              new BoolComboOption (
2396                      "show-region-gain-envelopes",
2397                      _("Show gain envelopes in audio regions"),
2398                      _("in all modes"),
2399                      _("only in Draw and Internal Edit modes"),
2400                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_region_gain),
2401                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_region_gain)
2402                      ));
2403
2404         add_option (_("Editor"), new OptionEditorHeading (_("Editor Behavior")));
2405
2406         add_option (_("Editor"),
2407              new BoolOption (
2408                      "automation-follows-regions",
2409                      _("Move relevant automation when audio regions are moved"),
2410                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_follows_regions),
2411                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_follows_regions)
2412                      ));
2413
2414         bo = new BoolOption (
2415                      "new-automation-points-on-lane",
2416                      _("Ignore Y-axis click position when adding new automation-points"),
2417                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_new_automation_points_on_lane),
2418                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_new_automation_points_on_lane)
2419                      );
2420         add_option (_("Editor"), bo);
2421         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2422                         _("<b>When enabled</b> The new points drawn in any automation lane will be placed on the existing line, regardless of mouse y-axis position."));
2423
2424         ComboOption<FadeShape>* fadeshape = new ComboOption<FadeShape> (
2425                         "default-fade-shape",
2426                         _("Default fade shape"),
2427                         sigc::mem_fun (*_rc_config,
2428                                 &RCConfiguration::get_default_fade_shape),
2429                         sigc::mem_fun (*_rc_config,
2430                                 &RCConfiguration::set_default_fade_shape)
2431                         );
2432
2433         fadeshape->add (FadeLinear,
2434                         _("Linear (for highly correlated material)"));
2435         fadeshape->add (FadeConstantPower, _("Constant power"));
2436         fadeshape->add (FadeSymmetric, _("Symmetric"));
2437         fadeshape->add (FadeSlow, _("Slow"));
2438         fadeshape->add (FadeFast, _("Fast"));
2439
2440         add_option (_("Editor"), fadeshape);
2441
2442         ComboOption<RegionEquivalence> *eqv = new ComboOption<RegionEquivalence> (
2443                      "region-equivalence",
2444                      _("Regions in active edit groups are edited together"),
2445                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_region_equivalence),
2446                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_region_equivalence)
2447                      );
2448
2449         eqv->add (Overlap, _("whenever they overlap in time"));
2450         eqv->add (Enclosed, _("if either encloses the other"));
2451         eqv->add (Exact, _("only if they have identical length, position and origin"));
2452
2453         add_option (_("Editor"), eqv);
2454
2455         ComboOption<LayerModel>* lm = new ComboOption<LayerModel> (
2456                 "layer-model",
2457                 _("Layering model"),
2458                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_layer_model),
2459                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_layer_model)
2460                 );
2461
2462         lm->add (LaterHigher, _("later is higher"));
2463         lm->add (Manual, _("manual layering"));
2464         add_option (_("Editor"), lm);
2465
2466         ComboOption<RegionSelectionAfterSplit> *rsas = new ComboOption<RegionSelectionAfterSplit> (
2467                     "region-selection-after-split",
2468                     _("After splitting selected regions, select"),
2469                     sigc::mem_fun (*_rc_config, &RCConfiguration::get_region_selection_after_split),
2470                     sigc::mem_fun (*_rc_config, &RCConfiguration::set_region_selection_after_split));
2471
2472         // TODO: decide which of these modes are really useful
2473         rsas->add(None, _("no regions"));
2474         // rsas->add(NewlyCreatedLeft, _("newly-created regions before the split"));
2475         // rsas->add(NewlyCreatedRight, _("newly-created regions after the split"));
2476         rsas->add(NewlyCreatedBoth, _("newly-created regions"));
2477         // rsas->add(Existing, _("unmodified regions in the existing selection"));
2478         // rsas->add(ExistingNewlyCreatedLeft, _("existing selection and newly-created regions before the split"));
2479         // rsas->add(ExistingNewlyCreatedRight, _("existing selection and newly-created regions after the split"));
2480         rsas->add(ExistingNewlyCreatedBoth, _("existing selection and newly-created regions"));
2481
2482         add_option (_("Editor"), rsas);
2483
2484         add_option (_("Editor/Snap"), new OptionEditorHeading (_("General Snap options:")));
2485
2486         add_option (_("Editor/Snap"),
2487                     new SpinOption<uint32_t> (
2488                             "snap-threshold",
2489                             _("Snap Threshold (pixels)"),
2490                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_snap_threshold),
2491                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_snap_threshold),
2492                             10, 200,
2493                             1, 10
2494                             ));
2495
2496         add_option (_("Editor/Snap"),
2497              new BoolOption (
2498                      "show-snapped-cursor",
2499                      _("Show \"snapped cursor\""),
2500                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_snapped_cursor),
2501                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_snapped_cursor)
2502                      ));
2503
2504         add_option (_("Editor/Snap"),
2505              new BoolOption (
2506                      "rubberbanding-snaps-to-grid",
2507                      _("Snap rubberband selection to grid"),
2508                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_rubberbanding_snaps_to_grid),
2509                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_rubberbanding_snaps_to_grid)
2510                      ));
2511
2512         add_option (_("Editor/Snap"),
2513              new BoolOption (
2514                      "grid-follows-internal",
2515                      _("Grid switches to alternate selection for Internal Edit tools"),
2516                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_grid_follows_internal),
2517                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_grid_follows_internal)
2518                      ));
2519
2520         add_option (_("Editor/Snap"),
2521              new BoolOption (
2522                      "rulers-follow-grid",
2523                      _("Rulers automatically change to follow the Grid mode selection"),
2524                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_rulers_follow_grid),
2525                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_rulers_follow_grid)
2526                      ));
2527
2528         add_option (_("Editor/Snap"), new OptionEditorHeading (_("When \"Snap\" is enabled, snap to:")));
2529
2530
2531         add_option (_("Editor/Snap"),
2532              new BoolOption (
2533                      "snap-to-marks",
2534                      _("Markers"),
2535                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_snap_to_marks),
2536                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_snap_to_marks)
2537                      ));
2538
2539         add_option (_("Editor/Snap"),
2540              new BoolOption (
2541                      "snap-to-region-sync",
2542                      _("Region Sync Points"),
2543                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_snap_to_region_sync),
2544                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_snap_to_region_sync)
2545                      ));
2546
2547         add_option (_("Editor/Snap"),
2548              new BoolOption (
2549                      "snap-to-region-start",
2550                      _("Region Starts"),
2551                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_snap_to_region_start),
2552                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_snap_to_region_start)
2553                      ));
2554
2555         add_option (_("Editor/Snap"),
2556              new BoolOption (
2557                      "snap-to-region-end",
2558                      _("Region Ends"),
2559                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_snap_to_region_end),
2560                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_snap_to_region_end)
2561                      ));
2562
2563         add_option (_("Editor/Snap"),
2564              new BoolOption (
2565                      "snap-to-grid",
2566                      _("Grid"),
2567                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_snap_to_grid),
2568                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_snap_to_grid)
2569                      ));
2570
2571         add_option (_("Editor/Modifiers"), new OptionEditorHeading (_("Keyboard Modifiers")));
2572         add_option (_("Editor/Modifiers"), new KeyboardOptions);
2573         add_option (_("Editor/Modifiers"), new OptionEditorBlank ());
2574
2575         /* MIXER -- SOLO AND MUTE */
2576
2577         add_option (_("Mixer"), new OptionEditorHeading (_("Solo")));
2578
2579         _solo_control_is_listen_control = new BoolOption (
2580                 "solo-control-is-listen-control",
2581                 _("Solo controls are Listen controls"),
2582                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_control_is_listen_control),
2583                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_control_is_listen_control)
2584                 );
2585
2586         add_option (_("Mixer"), _solo_control_is_listen_control);
2587
2588         add_option (_("Mixer"),
2589              new BoolOption (
2590                      "exclusive-solo",
2591                      _("Exclusive solo"),
2592                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_exclusive_solo),
2593                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_exclusive_solo)
2594                      ));
2595
2596         add_option (_("Mixer"),
2597              new BoolOption (
2598                      "show-solo-mutes",
2599                      _("Show solo muting"),
2600                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_show_solo_mutes),
2601                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_solo_mutes)
2602                      ));
2603
2604         add_option (_("Mixer"),
2605              new BoolOption (
2606                      "solo-mute-override",
2607                      _("Soloing overrides muting"),
2608                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_override),
2609                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_override)
2610                      ));
2611
2612         add_option (_("Mixer"),
2613              new FaderOption (
2614                      "solo-mute-gain",
2615                      _("Solo-in-place mute cut (dB)"),
2616                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_gain),
2617                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_gain)
2618                      ));
2619
2620         _listen_position = new ComboOption<ListenPosition> (
2621                 "listen-position",
2622                 _("Listen Position"),
2623                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_listen_position),
2624                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_listen_position)
2625                 );
2626
2627         _listen_position->add (AfterFaderListen, _("after-fader (AFL)"));
2628         _listen_position->add (PreFaderListen, _("pre-fader (PFL)"));
2629
2630         add_option (_("Mixer"), _listen_position);
2631
2632         ComboOption<PFLPosition>* pp = new ComboOption<PFLPosition> (
2633                 "pfl-position",
2634                 _("PFL signals come from"),
2635                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_pfl_position),
2636                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_pfl_position)
2637                 );
2638
2639         pp->add (PFLFromBeforeProcessors, _("before pre-fader processors"));
2640         pp->add (PFLFromAfterProcessors, _("pre-fader but after pre-fader processors"));
2641
2642         add_option (_("Mixer"), pp);
2643
2644         ComboOption<AFLPosition>* pa = new ComboOption<AFLPosition> (
2645                 "afl-position",
2646                 _("AFL signals come from"),
2647                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_afl_position),
2648                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_afl_position)
2649                 );
2650
2651         pa->add (AFLFromBeforeProcessors, _("immediately post-fader"));
2652         pa->add (AFLFromAfterProcessors, _("after post-fader processors (before pan)"));
2653
2654         add_option (_("Mixer"), pa);
2655
2656         add_option (_("Mixer"), new OptionEditorHeading (_("Default Track / Bus Muting Options")));
2657
2658         add_option (_("Mixer"),
2659              new BoolOption (
2660                      "mute-affects-pre-fader",
2661                      _("Mute affects pre-fader sends"),
2662                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_pre_fader),
2663                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_pre_fader)
2664                      ));
2665
2666         add_option (_("Mixer"),
2667              new BoolOption (
2668                      "mute-affects-post-fader",
2669                      _("Mute affects post-fader sends"),
2670                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_post_fader),
2671                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_post_fader)
2672                      ));
2673
2674         add_option (_("Mixer"),
2675              new BoolOption (
2676                      "mute-affects-control-outs",
2677                      _("Mute affects control outputs"),
2678                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_control_outs),
2679                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_control_outs)
2680                      ));
2681
2682         add_option (_("Mixer"),
2683              new BoolOption (
2684                      "mute-affects-main-outs",
2685                      _("Mute affects main outputs"),
2686                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_main_outs),
2687                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_main_outs)
2688                      ));
2689
2690
2691         if (!ARDOUR::Profile->get_mixbus()) {
2692                 add_option (_("Mixer"), new OptionEditorHeading (_("Send Routing")));
2693                 add_option (_("Mixer"),
2694                                 new BoolOption (
2695                                         "link-send-and-route-panner",
2696                                         _("Link panners of Aux and External Sends with main panner by default"),
2697                                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_link_send_and_route_panner),
2698                                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_link_send_and_route_panner)
2699                                         ));
2700         }
2701
2702         /* Signal Flow */
2703
2704         add_option (_("Signal Flow"), new OptionEditorHeading (_("Monitoring")));
2705
2706         ComboOption<MonitorModel>* mm = new ComboOption<MonitorModel> (
2707                 "monitoring-model",
2708                 _("Record monitoring handled by"),
2709                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_monitoring_model),
2710                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_monitoring_model)
2711                 );
2712
2713         if (AudioEngine::instance()->port_engine().can_monitor_input()) {
2714                 mm->add (HardwareMonitoring, _("via Audio Driver"));
2715         }
2716
2717         string prog (PROGRAM_NAME);
2718         boost::algorithm::to_lower (prog);
2719         mm->add (SoftwareMonitoring, string_compose (_("%1"), prog));
2720         mm->add (ExternalMonitoring, _("audio hardware"));
2721
2722         add_option (_("Signal Flow"), mm);
2723
2724         bo = new BoolOption (
2725                      "tape-machine-mode",
2726                      _("Tape machine mode"),
2727                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_tape_machine_mode),
2728                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_tape_machine_mode)
2729                      );
2730         add_option (_("Signal Flow"), bo);
2731         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2732                         string_compose (_("<b>When enabled</b> %1 will not monitor a track's input if the transport is stopped."),
2733                                         PROGRAM_NAME));
2734
2735         if (!Profile->get_mixbus()) {
2736
2737                 add_option (_("Signal Flow"), new OptionEditorHeading (_("Track and Bus Connections")));
2738
2739                 add_option (_("Signal Flow"),
2740                                 new BoolOption (
2741                                         "auto-connect-standard-busses",
2742                                         _("Auto-connect master/monitor busses"),
2743                                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_connect_standard_busses),
2744                                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_connect_standard_busses)
2745                                         ));
2746
2747                 ComboOption<AutoConnectOption>* iac = new ComboOption<AutoConnectOption> (
2748                                 "input-auto-connect",
2749                                 _("Connect track inputs"),
2750                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_input_auto_connect),
2751                                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_input_auto_connect)
2752                                 );
2753
2754                 iac->add (AutoConnectPhysical, _("automatically to physical inputs"));
2755                 iac->add (ManualConnect, _("manually"));
2756
2757                 add_option (_("Signal Flow"), iac);
2758
2759                 ComboOption<AutoConnectOption>* oac = new ComboOption<AutoConnectOption> (
2760                                 "output-auto-connect",
2761                                 _("Connect track and bus outputs"),
2762                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_output_auto_connect),
2763                                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_output_auto_connect)
2764                                 );
2765
2766                 oac->add (AutoConnectPhysical, _("automatically to physical outputs"));
2767                 oac->add (AutoConnectMaster, _("automatically to master bus"));
2768                 oac->add (ManualConnect, _("manually"));
2769
2770                 add_option (_("Signal Flow"), oac);
2771
2772                 bo = new BoolOption (
2773                                 "strict-io",
2774                                 _("Use 'Strict-I/O' for new tracks or busses"),
2775                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_strict_io),
2776                                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_strict_io)
2777                                 );
2778
2779                 add_option (_("Signal Flow"), bo);
2780                 Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2781                                 _("With strict-i/o enabled, Effect Processors will not modify the number of channels on a track. The number of output channels will always match the number of input channels."));
2782
2783         }  // !mixbus
2784
2785
2786         /* AUDIO */
2787
2788         add_option (_("Audio"), new OptionEditorHeading (_("Buffering")));
2789
2790         add_option (_("Audio"), new BufferingOptions (_rc_config));
2791
2792         add_option (_("Audio"), new OptionEditorHeading (_("Denormals")));
2793
2794         add_option (_("Audio"),
2795              new BoolOption (
2796                      "denormal-protection",
2797                      _("Use DC bias to protect against denormals"),
2798                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_protection),
2799                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_protection)
2800                      ));
2801
2802         ComboOption<DenormalModel>* dm = new ComboOption<DenormalModel> (
2803                 "denormal-model",
2804                 _("Processor handling"),
2805                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_model),
2806                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_model)
2807                 );
2808
2809         int dmsize = 1;
2810         dm->add (DenormalNone, _("no processor handling"));
2811
2812         FPU* fpu = FPU::instance();
2813
2814         if (fpu->has_flush_to_zero()) {
2815                 ++dmsize;
2816                 dm->add (DenormalFTZ, _("use FlushToZero"));
2817         } else if (_rc_config->get_denormal_model() == DenormalFTZ) {
2818                 _rc_config->set_denormal_model(DenormalNone);
2819         }
2820
2821         if (fpu->has_denormals_are_zero()) {
2822                 ++dmsize;
2823                 dm->add (DenormalDAZ, _("use DenormalsAreZero"));
2824         } else if (_rc_config->get_denormal_model() == DenormalDAZ) {
2825                 _rc_config->set_denormal_model(DenormalNone);
2826         }
2827
2828         if (fpu->has_flush_to_zero() && fpu->has_denormals_are_zero()) {
2829                 ++dmsize;
2830                 dm->add (DenormalFTZDAZ, _("use FlushToZero and DenormalsAreZero"));
2831         } else if (_rc_config->get_denormal_model() == DenormalFTZDAZ) {
2832                 _rc_config->set_denormal_model(DenormalNone);
2833         }
2834
2835         if (dmsize == 1) {
2836                 dm->set_sensitive(false);
2837         }
2838
2839         add_option (_("Audio"), dm);
2840
2841         add_option (_("Audio"), new OptionEditorHeading (_("Regions")));
2842
2843         add_option (_("Audio"),
2844              new BoolOption (
2845                      "auto-analyse-audio",
2846                      _("Enable automatic analysis of audio"),
2847                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_analyse_audio),
2848                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_analyse_audio)
2849                      ));
2850
2851         add_option (_("Audio"),
2852              new BoolOption (
2853                      "replicate-missing-region-channels",
2854                      _("Replicate missing region channels"),
2855                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_replicate_missing_region_channels),
2856                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_replicate_missing_region_channels)
2857                      ));
2858
2859         /* MIDI */
2860
2861         add_option (_("MIDI"), new OptionEditorHeading (_("Buffering")));
2862
2863         add_option (_("MIDI"),
2864                     new SpinOption<float> (
2865                             "midi-readahead",
2866                             _("MIDI read-ahead time (seconds)"),
2867                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_readahead),
2868                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_readahead),
2869                             0.1, 10, 0.05, 1,
2870                             "", 1.0, 2
2871                             ));
2872
2873         add_option (_("MIDI"), new OptionEditorHeading (_("Session")));
2874
2875         add_option (_("MIDI"),
2876              new SpinOption<int32_t> (
2877                      "initial-program-change",
2878                      _("Initial program change"),
2879                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_initial_program_change),
2880                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_initial_program_change),
2881                      -1, 65536, 1, 10
2882                      ));
2883
2884         add_option (_("MIDI"), new OptionEditorHeading (_("Audition")));
2885
2886         add_option (_("MIDI"),
2887              new BoolOption (
2888                      "sound-midi-notes",
2889                      _("Sound MIDI notes as they are selected in the editor"),
2890                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_sound_midi_notes),
2891                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_sound_midi_notes)
2892                      ));
2893
2894         ComboOption<std::string>* audition_synth = new ComboOption<std::string> (
2895                 "midi-audition-synth-uri",
2896                 _("MIDI Audition Synth (LV2)"),
2897                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_audition_synth_uri),
2898                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_audition_synth_uri)
2899                 );
2900
2901         audition_synth->add(X_(""), _("None"));
2902         PluginInfoList all_plugs;
2903         PluginManager& manager (PluginManager::instance());
2904 #ifdef LV2_SUPPORT
2905         all_plugs.insert (all_plugs.end(), manager.lv2_plugin_info().begin(), manager.lv2_plugin_info().end());
2906
2907         for (PluginInfoList::const_iterator i = all_plugs.begin(); i != all_plugs.end(); ++i) {
2908                 if (manager.get_status (*i) == PluginManager::Hidden) continue;
2909                 if (!(*i)->is_instrument()) continue;
2910                 if ((*i)->type != ARDOUR::LV2) continue;
2911                 if ((*i)->name.length() > 46) {
2912                         audition_synth->add((*i)->unique_id, (*i)->name.substr (0, 44) + "...");
2913                 } else {
2914                         audition_synth->add((*i)->unique_id, (*i)->name);
2915                 }
2916         }
2917 #endif
2918
2919         add_option (_("MIDI"), audition_synth);
2920
2921         /* Click */
2922
2923         add_option (_("Metronome"), new OptionEditorHeading (_("Metronome")));
2924         add_option (_("Metronome"), new ClickOptions (_rc_config));
2925         add_option (_("Metronome"), new OptionEditorHeading (_("Options")));
2926
2927         bo = new BoolOption (
2928                         "click-record-only",
2929                         _("Enable metronome only while recording"),
2930                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_click_record_only),
2931                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_click_record_only)
2932                         );
2933
2934         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2935                         string_compose (_("<b>When enabled</b> the metronome will remain silent if %1 is <b>not recording</b>."), PROGRAM_NAME));
2936         add_option (_("Metronome"), bo);
2937         add_option (_("Metronome"), new OptionEditorBlank ());
2938
2939
2940         /* Meters */
2941
2942         add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Metering")));
2943
2944         ComboOption<float>* mht = new ComboOption<float> (
2945                 "meter-hold",
2946                 _("Peak hold time"),
2947                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_hold),
2948                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_hold)
2949                 );
2950
2951         mht->add (MeterHoldOff, _("off"));
2952         mht->add (MeterHoldShort, _("short"));
2953         mht->add (MeterHoldMedium, _("medium"));
2954         mht->add (MeterHoldLong, _("long"));
2955
2956         add_option (S_("Preferences|Metering"), mht);
2957
2958         ComboOption<float>* mfo = new ComboOption<float> (
2959                 "meter-falloff",
2960                 _("DPM fall-off"),
2961                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_falloff),
2962                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_falloff)
2963                 );
2964
2965         mfo->add (METER_FALLOFF_OFF,      _("off"));
2966         mfo->add (METER_FALLOFF_SLOWEST,  _("slowest [6.6dB/sec]"));
2967         mfo->add (METER_FALLOFF_SLOW,     _("slow [8.6dB/sec] (BBC PPM, EBU PPM)"));
2968         mfo->add (METER_FALLOFF_SLOWISH,  _("moderate [12.0dB/sec] (DIN)"));
2969         mfo->add (METER_FALLOFF_MODERATE, _("medium [13.3dB/sec] (EBU Digi PPM, IRT Digi PPM)"));
2970         mfo->add (METER_FALLOFF_MEDIUM,   _("fast [20dB/sec]"));
2971         mfo->add (METER_FALLOFF_FAST,     _("very fast [32dB/sec]"));
2972
2973         add_option (S_("Preferences|Metering"), mfo);
2974
2975         ComboOption<MeterLineUp>* mlu = new ComboOption<MeterLineUp> (
2976                 "meter-line-up-level",
2977                 _("Meter line-up level; 0dBu"),
2978                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_line_up_level),
2979                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_line_up_level)
2980                 );
2981
2982         mlu->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
2983         mlu->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
2984         mlu->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
2985         mlu->add (MeteringLineUp15, _("-15dBFS (DIN)"));
2986
2987         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."));
2988
2989         add_option (S_("Preferences|Metering"), mlu);
2990
2991         ComboOption<MeterLineUp>* mld = new ComboOption<MeterLineUp> (
2992                 "meter-line-up-din",
2993                 _("IEC1/DIN Meter line-up level; 0dBu"),
2994                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_line_up_din),
2995                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_line_up_din)
2996                 );
2997
2998         mld->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
2999         mld->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
3000         mld->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
3001         mld->add (MeteringLineUp15, _("-15dBFS (DIN)"));
3002
3003         Gtkmm2ext::UI::instance()->set_tip (mld->tip_widget(), _("Reference level for IEC1/DIN meter."));
3004
3005         add_option (S_("Preferences|Metering"), mld);
3006
3007         ComboOption<VUMeterStandard>* mvu = new ComboOption<VUMeterStandard> (
3008                 "meter-vu-standard",
3009                 _("VU Meter standard"),
3010                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_vu_standard),
3011                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_vu_standard)
3012                 );
3013
3014         mvu->add (MeteringVUfrench,   _("0VU = -2dBu (France)"));
3015         mvu->add (MeteringVUamerican, _("0VU = 0dBu (North America, Australia)"));
3016         mvu->add (MeteringVUstandard, _("0VU = +4dBu (standard)"));
3017         mvu->add (MeteringVUeight,    _("0VU = +8dBu"));
3018
3019         add_option (S_("Preferences|Metering"), mvu);
3020
3021         HSliderOption *mpks = new HSliderOption("meter-peak",
3022                         _("Peak indicator threshold [dBFS]"),
3023                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_peak),
3024                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_peak),
3025                         -10, 0, .1, .1
3026                         );
3027
3028         Gtkmm2ext::UI::instance()->set_tip (
3029                         mpks->tip_widget(),
3030                         _("Specify the audio signal level in dBFS at and above which the meter-peak indicator will flash red."));
3031
3032         add_option (S_("Preferences|Metering"), mpks);
3033
3034         OptionEditorHeading* default_meter_head = new OptionEditorHeading (_("Default Meter Types"));
3035         default_meter_head->set_note (_("These settings apply to newly created tracks and busses. For the Master bus, this will be when a new session is created."));
3036
3037         add_option (S_("Preferences|Metering"), default_meter_head);
3038
3039         ComboOption<MeterType>* mtm = new ComboOption<MeterType> (
3040                 "meter-type-master",
3041                 _("Default Meter Type for Master Bus"),
3042                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_master),
3043                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_master)
3044                 );
3045         mtm->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
3046         mtm->add (MeterK20,     ArdourMeter::meter_type_string(MeterK20));
3047         mtm->add (MeterK14,     ArdourMeter::meter_type_string(MeterK14));
3048         mtm->add (MeterK12,     ArdourMeter::meter_type_string(MeterK12));
3049         mtm->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
3050         mtm->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
3051         mtm->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
3052         mtm->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
3053
3054         add_option (S_("Preferences|Metering"), mtm);
3055
3056
3057         ComboOption<MeterType>* mtb = new ComboOption<MeterType> (
3058                 "meter-type-bus",
3059                 _("Default meter type for busses"),
3060                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_bus),
3061                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_bus)
3062                 );
3063         mtb->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
3064         mtb->add (MeterK20,     ArdourMeter::meter_type_string(MeterK20));
3065         mtb->add (MeterK14,     ArdourMeter::meter_type_string(MeterK14));
3066         mtb->add (MeterK12,     ArdourMeter::meter_type_string(MeterK12));
3067         mtb->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
3068         mtb->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
3069         mtb->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
3070         mtb->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
3071
3072         add_option (S_("Preferences|Metering"), mtb);
3073
3074         ComboOption<MeterType>* mtt = new ComboOption<MeterType> (
3075                 "meter-type-track",
3076                 _("Default meter type for tracks"),
3077                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_track),
3078                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_track)
3079                 );
3080         mtt->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
3081         mtt->add (MeterPeak0dB, ArdourMeter::meter_type_string(MeterPeak0dB));
3082
3083         add_option (S_("Preferences|Metering"), mtt);
3084
3085         add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Post Export Analysis")));
3086
3087         add_option (S_("Preferences|Metering"),
3088              new BoolOption (
3089                      "save-export-analysis-image",
3090                      _("Save loudness analysis as image file"),
3091                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_save_export_analysis_image),
3092                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_save_export_analysis_image)
3093                      ));
3094
3095         /* TRANSPORT & Sync */
3096
3097         add_option (_("Transport"), new OptionEditorHeading (_("General")));
3098
3099         bo = new BoolOption (
3100                      "stop-at-session-end",
3101                      _("Stop at the end of the session"),
3102                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_at_session_end),
3103                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_at_session_end)
3104                      );
3105         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3106                                             string_compose (_("<b>When enabled</b> if %1 is <b>not recording</b>, it will stop the transport "
3107                                                               "when it reaches the current session end marker\n\n"
3108                                                               "<b>When disabled</b> %1 will continue to roll past the session end marker at all times"),
3109                                                             PROGRAM_NAME));
3110         add_option (_("Transport"), bo);
3111
3112         bo = new BoolOption (
3113                      "latched-record-enable",
3114                      _("Keep record-enable engaged on stop"),
3115                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_latched_record_enable),
3116                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_latched_record_enable)
3117                      );
3118         add_option (_("Transport"), bo);
3119         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3120                         _("<b>When enabled</b> master record will remain engaged when the transport transitions to stop.\n<b>When disabled</b> master record will be disabled when the transport transitions to stop."));
3121
3122         bo = new BoolOption (
3123                      "disable-disarm-during-roll",
3124                      _("Disable per-track record disarm while rolling"),
3125                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_disable_disarm_during_roll),
3126                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_disable_disarm_during_roll)
3127                      );
3128         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(), _("<b>When enabled</b> this will prevent you from accidentally stopping specific tracks recording during a take."));
3129         add_option (_("Transport"), bo);
3130
3131         bo = new BoolOption (
3132                      "quieten_at_speed",
3133                      _("12dB gain reduction during fast-forward and fast-rewind"),
3134                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_quieten_at_speed),
3135                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_quieten_at_speed)
3136                      );
3137         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3138                         _("<b>When enabled</b> this will reduce the unpleasant increase in perceived volume "
3139                                 "that occurs when fast-forwarding or rewinding through some kinds of audio"));
3140         add_option (_("Transport"), bo);
3141
3142         ComboOption<float>* psc = new ComboOption<float> (
3143                      "preroll-seconds",
3144                      _("Preroll"),
3145                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_preroll_seconds),
3146                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_preroll_seconds)
3147                      );
3148         Gtkmm2ext::UI::instance()->set_tip (psc->tip_widget(),
3149                                             (_("The amount of preroll to apply when <b>Play with Preroll</b> or <b>Record with Preroll</b>is initiated.\n\n"
3150                                                "If <b>Follow Edits</b> is enabled, the preroll is applied to the playhead position when a region is selected or trimmed.")));
3151         psc->add (-4.0, _("4 Bars"));
3152         psc->add (-2.0, _("2 Bars"));
3153         psc->add (-1.0, _("1 Bar"));
3154         psc->add (0.0, _("0 (no pre-roll)"));
3155         psc->add (0.1, _("0.1 second"));
3156         psc->add (0.25, _("0.25 second"));
3157         psc->add (0.5, _("0.5 second"));
3158         psc->add (1.0, _("1.0 second"));
3159         psc->add (2.0, _("2.0 seconds"));
3160         add_option (_("Transport"), psc);
3161
3162
3163         add_option (_("Transport"), new OptionEditorHeading (_("Looping")));
3164
3165         bo = new BoolOption (
3166                      "loop-is-mode",
3167                      _("Play loop is a transport mode"),
3168                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_loop_is_mode),
3169                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_loop_is_mode)
3170                      );
3171         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3172                                             (_("<b>When enabled</b> the loop button does not start playback but forces playback to always play the loop\n\n"
3173                                                "<b>When disabled</b> the loop button starts playing the loop, but stop then cancels loop playback")));
3174         add_option (_("Transport"), bo);
3175
3176         bo = new BoolOption (
3177                      "seamless-loop",
3178                      _("Do seamless looping (not possible when slaved to MTC, LTC etc)"),
3179                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_seamless_loop),
3180                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_seamless_loop)
3181                      );
3182         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3183                                             string_compose (_("<b>When enabled</b> this will loop by reading ahead and wrapping around at the loop point, "
3184                                                               "preventing any need to do a transport locate at the end of the loop\n\n"
3185                                                               "<b>When disabled</b> looping is done by locating back to the start of the loop when %1 reaches the end "
3186                                                               "which will often cause a small click or delay"), PROGRAM_NAME));
3187         add_option (_("Transport"), bo);
3188
3189         add_option (_("Transport"), new OptionEditorHeading (_("Dropout (xrun) Handling")));
3190         bo = new BoolOption (
3191                      "stop-recording-on-xrun",
3192                      _("Stop recording when an xrun occurs"),
3193                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_recording_on_xrun),
3194                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_recording_on_xrun)
3195                      );
3196         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3197                                             string_compose (_("<b>When enabled</b> %1 will stop recording if an over- or underrun is detected by the audio engine"),
3198                                                             PROGRAM_NAME));
3199         add_option (_("Transport"), bo);
3200
3201         bo = new BoolOption (
3202                      "create-xrun-marker",
3203                      _("Create markers where xruns occur"),
3204                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_create_xrun_marker),
3205                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_create_xrun_marker)
3206                      );
3207         add_option (_("Transport"), bo);
3208
3209
3210         /* SYNC */
3211
3212         add_option (_("Sync"), new OptionEditorHeading (_("Transport Masters")));
3213
3214         add_option (_("Sync"), new WidgetOption (X_("foo"), X_("Transport Masters"), _transport_masters_widget));
3215
3216         _sync_framerate = new BoolOption (
3217                      "timecode-sync-frame-rate",
3218                      _("Match session video frame rate to external timecode"),
3219                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_sync_frame_rate),
3220                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_sync_frame_rate)
3221                      );
3222         Gtkmm2ext::UI::instance()->set_tip
3223                 (_sync_framerate->tip_widget(),
3224                  string_compose (_("This option controls the value of the video frame rate <i>while chasing</i> an external timecode source.\n\n"
3225                                    "<b>When enabled</b> the session video frame rate will be changed to match that of the selected external timecode source.\n\n"
3226                                    "<b>When disabled</b> the session video frame rate will not be changed to match that of the selected external timecode source."
3227                                    "Instead the frame rate indication in the main clock will flash red and %1 will convert between the external "
3228                                    "timecode standard and the session standard."), PROGRAM_NAME));
3229
3230         add_option (_("Sync"), _sync_framerate);
3231
3232         add_option (_("Sync/LTC"), new OptionEditorHeading (_("Linear Timecode (LTC) Generator")));
3233
3234         add_option (_("Sync/LTC"),
3235                     new BoolOption (
3236                             "send-ltc",
3237                             _("Enable LTC generator"),
3238                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_ltc),
3239                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_ltc)
3240                             ));
3241
3242         _ltc_send_continuously = new BoolOption (
3243                             "ltc-send-continuously",
3244                             _("Send LTC while stopped"),
3245                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_send_continuously),
3246                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_send_continuously)
3247                             );
3248         Gtkmm2ext::UI::instance()->set_tip
3249                 (_ltc_send_continuously->tip_widget(),
3250                  string_compose (_("<b>When enabled</b> %1 will continue to send LTC information even when the transport (playhead) is not moving"), PROGRAM_NAME));
3251         add_option (_("Sync/LTC"), _ltc_send_continuously);
3252
3253         _ltc_volume_slider = new HSliderOption("ltcvol", _("LTC generator level [dBFS]"),
3254                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_output_volume),
3255                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_output_volume),
3256                                         -50, 0, .5, 5,
3257                                         .05, true);
3258
3259         Gtkmm2ext::UI::instance()->set_tip
3260                 (_ltc_volume_slider->tip_widget(),
3261                  _("Specify the Peak Volume of the generated LTC signal in dBFS. A good value is  0dBu ^= -18dBFS in an EBU calibrated system"));
3262
3263         add_option (_("Sync/LTC"), _ltc_volume_slider);
3264
3265
3266         add_option (_("Sync/MIDI"), new OptionEditorHeading (_("MIDI Beat Clock (Mclk) Generator")));
3267
3268         add_option (_("Sync/MIDI"),
3269                     new BoolOption (
3270                             "send-midi-clock",
3271                             _("Enable Mclk generator"),
3272                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_midi_clock),
3273                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_midi_clock)
3274                             ));
3275
3276         add_option (_("Sync/MIDI"), new OptionEditorHeading (_("MIDI Time Code (MTC) Generator")));
3277
3278         add_option (_("Sync/MIDI"),
3279                     new BoolOption (
3280                             "send-mtc",
3281                             _("Enable MTC Generator"),
3282                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mtc),
3283                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mtc)
3284                             ));
3285
3286         add_option (_("Sync/MIDI"),
3287                     new SpinOption<int> (
3288                             "mtc-qf-speed-tolerance",
3289                             _("Percentage either side of normal transport speed to transmit MTC"),
3290                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mtc_qf_speed_tolerance),
3291                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mtc_qf_speed_tolerance),
3292                             0, 20, 1, 5
3293                             ));
3294
3295         add_option (_("Sync/MIDI"), new OptionEditorHeading (_("MIDI Machine Control (MMC)")));
3296
3297         add_option (_("Sync/MIDI"),
3298                     new BoolOption (
3299                             "mmc-control",
3300                             _("Respond to MMC commands"),
3301                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_control),
3302                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_control)
3303                             ));
3304
3305         add_option (_("Sync/MIDI"),
3306                     new BoolOption (
3307                             "send-mmc",
3308                             _("Send MMC commands"),
3309                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mmc),
3310                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mmc)
3311                             ));
3312
3313         add_option (_("Sync/MIDI"),
3314              new SpinOption<uint8_t> (
3315                      "mmc-receive-device-id",
3316                      _("Inbound MMC device ID"),
3317                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_receive_device_id),
3318                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_receive_device_id),
3319                      0, 127, 1, 10
3320                      ));
3321
3322         add_option (_("Sync/MIDI"),
3323              new SpinOption<uint8_t> (
3324                      "mmc-send-device-id",
3325                      _("Outbound MMC device ID"),
3326                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_send_device_id),
3327                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_send_device_id),
3328                      0, 127, 1, 10
3329                      ));
3330
3331
3332         /* Control Surfaces */
3333
3334         add_option (_("Control Surfaces"), new OptionEditorHeading (_("Control Surfaces")));
3335         add_option (_("Control Surfaces"), new ControlSurfacesOptions ());
3336
3337         /* MIDI PORTs */
3338         add_option (_("MIDI Ports"), new OptionEditorHeading (_("MIDI Port Options")));
3339
3340         add_option (_("MIDI Ports"),
3341                     new BoolOption (
3342                             "midi-input-follows-selection",
3343                             _("MIDI input follows MIDI track selection"),
3344                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_input_follows_selection),
3345                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_input_follows_selection)
3346                             ));
3347
3348         add_option (_("MIDI Ports"), new MidiPortOptions ());
3349         add_option (_("MIDI Ports"), new OptionEditorBlank ());
3350
3351         /* PLUGINS */
3352
3353 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT || defined AUDIOUNIT_SUPPORT)
3354         add_option (_("Plugins"), new OptionEditorHeading (_("Scan/Discover")));
3355         add_option (_("Plugins"),
3356                         new RcActionButton (_("Scan for Plugins"),
3357                                 sigc::mem_fun (*this, &RCOptionEditor::plugin_scan_refresh)));
3358
3359 #endif
3360
3361         add_option (_("Plugins"), new OptionEditorHeading (_("General")));
3362
3363 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT || defined AUDIOUNIT_SUPPORT)
3364         bo = new BoolOption (
3365                         "show-plugin-scan-window",
3366                         _("Always Display Plugin Scan Progress"),
3367                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_plugin_scan_window),
3368                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_plugin_scan_window)
3369                         );
3370         add_option (_("Plugins"), bo);
3371         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3372                         _("<b>When enabled</b> a popup window showing plugin scan progress is displayed for indexing (cache load) and discovery (detect new plugins)"));
3373 #endif
3374
3375         bo = new BoolOption (
3376                 "plugins-stop-with-transport",
3377                 _("Silence plugins when the transport is stopped"),
3378                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugins_stop_with_transport),
3379                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_plugins_stop_with_transport)
3380                 );
3381         add_option (_("Plugins"), bo);
3382         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3383                                             _("<b>When enabled</b> plugins will be reset at transport stop. When disabled plugins will be left unchanged at transport stop.\n\nThis mostly affects plugins with a \"tail\" like Reverbs."));
3384
3385         bo = new BoolOption (
3386                 "new-plugins-active",
3387                         _("Make new plugins active"),
3388                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_new_plugins_active),
3389                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_new_plugins_active)
3390                         );
3391         add_option (_("Plugins"), bo);
3392         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3393                                             _("<b>When enabled</b> plugins will be activated when they are added to tracks/busses. When disabled plugins will be left inactive when they are added to tracks/busses"));
3394
3395 #if (defined WINDOWS_VST_SUPPORT || defined MACVST_SUPPORT || defined LXVST_SUPPORT)
3396         add_option (_("Plugins/VST"), new OptionEditorHeading (_("VST")));
3397 #if 0
3398         add_option (_("Plugins/VST"),
3399                         new RcActionButton (_("Scan for Plugins"),
3400                                 sigc::mem_fun (*this, &RCOptionEditor::plugin_scan_refresh)));
3401 #endif
3402
3403 #if (defined AUDIOUNIT_SUPPORT && defined MACVST_SUPPORT)
3404         bo = new BoolOption (
3405                         "",
3406                         _("Enable Mac VST support (requires restart or re-scan)"),
3407                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_use_macvst),
3408                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_use_macvst)
3409                         );
3410         add_option (_("Plugins/VST"), bo);
3411 #endif
3412
3413         bo = new BoolOption (
3414                         "discover-vst-on-start",
3415                         _("Scan for [new] VST Plugins on Application Start"),
3416                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_discover_vst_on_start),
3417                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_discover_vst_on_start)
3418                         );
3419         add_option (_("Plugins/VST"), bo);
3420         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3421                                             _("<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"));
3422
3423 #ifdef WINDOWS_VST_SUPPORT
3424         // currently verbose logging is only implemented for Windows VST.
3425         bo = new BoolOption (
3426                         "verbose-plugin-scan",
3427                         _("Verbose Plugin Scan"),
3428                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_verbose_plugin_scan),
3429                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_verbose_plugin_scan)
3430                         );
3431         add_option (_("Plugins/VST"), bo);
3432         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3433                                             _("<b>When enabled</b> additional information for every plugin is added to the Log Window."));
3434 #endif
3435
3436         add_option (_("Plugins/VST"), new VstTimeOutSliderOption (_rc_config));
3437
3438         add_option (_("Plugins/VST"),
3439                         new RcActionButton (_("Clear"),
3440                                 sigc::mem_fun (*this, &RCOptionEditor::clear_vst_cache),
3441                                 _("VST Cache:")));
3442
3443         add_option (_("Plugins/VST"),
3444                         new RcActionButton (_("Clear"),
3445                                 sigc::mem_fun (*this, &RCOptionEditor::clear_vst_blacklist),
3446                                 _("VST Blacklist:")));
3447 #endif
3448
3449 #ifdef LXVST_SUPPORT
3450         add_option (_("Plugins/VST"),
3451                         new RcActionButton (_("Edit"),
3452                                 sigc::mem_fun (*this, &RCOptionEditor::edit_lxvst_path),
3453                         _("Linux VST Path:")));
3454
3455         add_option (_("Plugins/VST"),
3456                         new RcConfigDisplay (
3457                                 "plugin-path-lxvst",
3458                                 _("Path:"),
3459                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugin_path_lxvst),
3460                                 0));
3461 #endif
3462
3463 #ifdef WINDOWS_VST_SUPPORT
3464         add_option (_("Plugins/VST"),
3465                         new RcActionButton (_("Edit"),
3466                                 sigc::mem_fun (*this, &RCOptionEditor::edit_vst_path),
3467                         _("Windows VST Path:")));
3468         add_option (_("Plugins/VST"),
3469                         new RcConfigDisplay (
3470                                 "plugin-path-vst",
3471                                 _("Path:"),
3472                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugin_path_vst),
3473                                 ';'));
3474 #endif
3475
3476 #ifdef AUDIOUNIT_SUPPORT
3477
3478         add_option (_("Plugins/Audio Unit"), new OptionEditorHeading (_("Audio Unit")));
3479 #if 0
3480         add_option (_("Plugins/Audio Unit"),
3481                         new RcActionButton (_("Scan for Plugins"),
3482                                 sigc::mem_fun (*this, &RCOptionEditor::plugin_scan_refresh)));
3483 #endif
3484
3485         bo = new BoolOption (
3486                         "discover-audio-units",
3487                         _("Scan for [new] AudioUnit Plugins on Application Start"),
3488                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_discover_audio_units),
3489                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_discover_audio_units)
3490                         );
3491         add_option (_("Plugins/Audio Unit"), bo);
3492         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3493                                             _("<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."));
3494
3495         add_option (_("Plugins/Audio Unit"),
3496                         new RcActionButton (_("Clear"),
3497                                 sigc::mem_fun (*this, &RCOptionEditor::clear_au_cache),
3498                                 _("AU Cache:")));
3499
3500         add_option (_("Plugins/Audio Unit"),
3501                         new RcActionButton (_("Clear"),
3502                                 sigc::mem_fun (*this, &RCOptionEditor::clear_au_blacklist),
3503                                 _("AU Blacklist:")));
3504 #endif
3505
3506 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT || defined AUDIOUNIT_SUPPORT || defined HAVE_LV2)
3507         add_option (_("Plugins"), new OptionEditorHeading (_("Plugin GUI")));
3508         add_option (_("Plugins"),
3509              new BoolOption (
3510                      "open-gui-after-adding-plugin",
3511                      _("Automatically open the plugin GUI when adding a new plugin"),
3512                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_open_gui_after_adding_plugin),
3513                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_open_gui_after_adding_plugin)
3514                      ));
3515
3516 #if (defined LV2_SUPPORT && defined LV2_EXTENDED)
3517         add_option (_("Plugins"),
3518              new BoolOption (
3519                      "show-inline-display-by-default",
3520                      _("Show Plugin Inline Display on Mixerstrip by default"),
3521                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_inline_display_by_default),
3522                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_inline_display_by_default)
3523                      ));
3524
3525         _plugin_prefer_inline = new BoolOption (
3526                         "prefer-inline-over-gui",
3527                         _("Don't automatically open the plugin GUI when the plugin has an inline display mode"),
3528                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_prefer_inline_over_gui),
3529                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_prefer_inline_over_gui)
3530                         );
3531         add_option (_("Plugins"), _plugin_prefer_inline);
3532 #endif
3533
3534         add_option (_("Plugins"), new OptionEditorHeading (_("Instrument")));
3535
3536         bo = new BoolOption (
3537                         "ask-replace-instrument",
3538                         _("Ask to replace existing instrument plugin"),
3539                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_ask_replace_instrument),
3540                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_ask_replace_instrument)
3541                         );
3542         add_option (_("Plugins"), bo);
3543
3544         bo = new BoolOption (
3545                         "ask-setup_instrument",
3546                         _("Interactively configure instrument plugins on insert"),
3547                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_ask_setup_instrument),
3548                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_ask_setup_instrument)
3549                         );
3550         add_option (_("Plugins"), bo);
3551         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3552                         _("<b>When enabled</b> show a dialog to select instrument channel configuration before adding a multichannel plugin."));
3553
3554 #endif
3555         add_option (_("Plugins"), new OptionEditorBlank ());
3556
3557         /* INTERFACE */
3558 #if (defined OPTIONAL_CAIRO_IMAGE_SURFACE || defined CAIRO_SUPPORTS_FORCE_BUGGY_GRADIENTS_ENVIRONMENT_VARIABLE)
3559         add_option (_("Appearance"), new OptionEditorHeading (_("Graphics Acceleration")));
3560 #endif
3561
3562 #ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
3563         BoolOption* bgc = new BoolOption (
3564                 "cairo-image-surface",
3565                 _("Disable Graphics Hardware Acceleration (requires restart)"),
3566                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_cairo_image_surface),
3567                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_cairo_image_surface)
3568                 );
3569
3570         Gtkmm2ext::UI::instance()->set_tip (bgc->tip_widget(), string_compose (
3571                                 _("Render large parts of the application user-interface in software, instead of using 2D-graphics acceleration.\nThis requires restarting %1 before having an effect"), PROGRAM_NAME));
3572         add_option (_("Appearance"), bgc);
3573 #endif
3574
3575 #ifdef CAIRO_SUPPORTS_FORCE_BUGGY_GRADIENTS_ENVIRONMENT_VARIABLE
3576         BoolOption* bgo = new BoolOption (
3577                 "buggy-gradients",
3578                 _("Possibly improve slow graphical performance (requires restart)"),
3579                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_buggy_gradients),
3580                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_buggy_gradients)
3581                 );
3582
3583         Gtkmm2ext::UI::instance()->set_tip (bgo->tip_widget(), string_compose (_("Disables hardware gradient rendering on buggy video drivers (\"buggy gradients patch\").\nThis requires restarting %1 before having an effect"), PROGRAM_NAME));
3584         add_option (_("Appearance"), bgo);
3585 #endif
3586         add_option (_("Appearance"), new OptionEditorHeading (_("Graphical User Interface")));
3587
3588         add_option (_("Appearance"),
3589              new BoolOption (
3590                      "widget-prelight",
3591                      _("Highlight widgets on mouseover"),
3592                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_widget_prelight),
3593                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_widget_prelight)
3594                      ));
3595
3596         add_option (_("Appearance"),
3597              new BoolOption (
3598                      "use-tooltips",
3599                      _("Show tooltips if mouse hovers over a control"),
3600                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_tooltips),
3601                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_tooltips)
3602                      ));
3603
3604         bo = new BoolOption (
3605                         "super-rapid-clock-update",
3606                         _("Update clocks at TC Frame rate"),
3607                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_super_rapid_clock_update),
3608                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_super_rapid_clock_update)
3609                         );
3610         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3611                         _("<b>When enabled</b> clock displays are updated every Timecode Frame (fps).\n\n"
3612                                 "<b>When disabled</b> clock displays are updated only every 100ms."
3613                          ));
3614         add_option (_("Appearance"), bo);
3615
3616         add_option (_("Appearance"),
3617                         new BoolOption (
3618                                 "blink-rec-arm",
3619                                 _("Blink Rec-Arm buttons"),
3620                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_blink_rec_arm),
3621                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_blink_rec_arm)
3622                                 ));
3623
3624         add_option (_("Appearance"),
3625                         new BoolOption (
3626                                 "blink-alert-indicators",
3627                                 _("Blink Alert Indicators"),
3628                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_blink_alert_indicators),
3629                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_blink_alert_indicators)
3630                                 ));
3631
3632
3633 #ifndef __APPLE__
3634         /* font scaling does nothing with GDK/Quartz */
3635         add_option (_("Appearance"), new FontScalingOptions ());
3636 #endif
3637         add_option (_("Appearance/Editor"), new OptionEditorHeading (_("General")));
3638         add_option (_("Appearance/Editor"),
3639              new BoolOption (
3640                      "show-name-highlight",
3641                      _("Use name highlight bars in region displays (requires a restart)"),
3642                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_name_highlight),
3643                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_name_highlight)
3644                      ));
3645
3646         add_option (_("Appearance/Editor"),
3647                         new BoolOption (
3648                         "color-regions-using-track-color",
3649                         _("Region color follows track color"),
3650                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_color_regions_using_track_color),
3651                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_color_regions_using_track_color)
3652                         ));
3653
3654         add_option (_("Appearance/Editor"), new OptionEditorHeading (_("Waveforms")));
3655
3656         if (!Profile->get_mixbus()) {
3657                 add_option (_("Appearance/Editor"),
3658                                 new BoolOption (
3659                                         "show-waveforms",
3660                                         _("Show waveforms in regions"),
3661                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveforms),
3662                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveforms)
3663                                         ));
3664         }  // !mixbus
3665
3666         add_option (_("Appearance/Editor"),
3667              new BoolOption (
3668                      "show-waveforms-while-recording",
3669                      _("Show waveforms while recording"),
3670                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveforms_while_recording),
3671                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveforms_while_recording)
3672                      ));
3673
3674         add_option (_("Appearance/Editor"),
3675                         new BoolOption (
3676                         "show-waveform-clipping",
3677                         _("Show waveform clipping"),
3678                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveform_clipping),
3679                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveform_clipping)
3680                         ));
3681
3682         add_option (_("Appearance/Editor"), new ClipLevelOptions ());
3683
3684         ComboOption<WaveformScale>* wfs = new ComboOption<WaveformScale> (
3685                 "waveform-scale",
3686                 _("Waveform scale"),
3687                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_scale),
3688                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_scale)
3689                 );
3690
3691         wfs->add (Linear, _("linear"));
3692         wfs->add (Logarithmic, _("logarithmic"));
3693
3694         add_option (_("Appearance/Editor"), wfs);
3695
3696         ComboOption<WaveformShape>* wfsh = new ComboOption<WaveformShape> (
3697                 "waveform-shape",
3698                 _("Waveform shape"),
3699                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_shape),
3700                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_shape)
3701                 );
3702
3703         wfsh->add (Traditional, _("traditional"));
3704         wfsh->add (Rectified, _("rectified"));
3705
3706         add_option (_("Appearance/Editor"), wfsh);
3707
3708         add_option (_("Appearance/Editor"), new OptionEditorHeading (_("Editor Meters")));
3709
3710         add_option (_("Appearance/Editor"),
3711              new BoolOption (
3712                      "show-track-meters",
3713                      _("Show meters in track headers"),
3714                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_track_meters),
3715                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_track_meters)
3716                      ));
3717
3718         add_option (_("Appearance/Editor"),
3719              new BoolOption (
3720                      "editor-stereo-only-meters",
3721                      _("Limit track header meters to stereo"),
3722                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_editor_stereo_only_meters),
3723                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_editor_stereo_only_meters)
3724                      ));
3725
3726         add_option (_("Appearance/Editor"), new OptionEditorHeading (_("MIDI Regions")));
3727
3728         add_option (_("Appearance/Editor"),
3729                     new BoolOption (
3730                             "display-first-midi-bank-as-zero",
3731                             _("Display first MIDI bank/program as 0"),
3732                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_first_midi_bank_is_zero),
3733                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_first_midi_bank_is_zero)
3734                             ));
3735
3736         add_option (_("Appearance/Editor"),
3737              new BoolOption (
3738                      "never-display-periodic-midi",
3739                      _("Don't display periodic (MTC, MMC) SysEx messages in MIDI Regions"),
3740                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_never_display_periodic_midi),
3741                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_never_display_periodic_midi)
3742                      ));
3743
3744
3745         add_option (_("Appearance/Editor"),
3746                     new BoolOption (
3747                             "use-note-bars-for-velocity",
3748                             _("Show velocity horizontally inside notes"),
3749                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_note_bars_for_velocity),
3750                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_note_bars_for_velocity)
3751                             ));
3752
3753         add_option (_("Appearance/Editor"),
3754                     new BoolOption (
3755                             "use-note-color-for-velocity",
3756                             _("Use colors to show note velocity"),
3757                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_note_color_for_velocity),
3758                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_note_color_for_velocity)
3759                             ));
3760
3761         add_option (_("Appearance/Editor"), new OptionEditorBlank ());
3762
3763         /* The names of these controls must be the same as those given in MixerStrip
3764            for the actual widgets being controlled.
3765         */
3766         _mixer_strip_visibility.add (0, X_("Input"), _("Input"));
3767         _mixer_strip_visibility.add (0, X_("PhaseInvert"), _("Phase Invert"));
3768         _mixer_strip_visibility.add (0, X_("RecMon"), _("Record & Monitor"));
3769         _mixer_strip_visibility.add (0, X_("SoloIsoLock"), _("Solo Iso / Lock"));
3770         _mixer_strip_visibility.add (0, X_("Output"), _("Output"));
3771         _mixer_strip_visibility.add (0, X_("Comments"), _("Comments"));
3772         _mixer_strip_visibility.add (0, X_("VCA"), _("VCA Assigns"));
3773
3774         add_option (_("Appearance/Mixer"),
3775                 new VisibilityOption (
3776                         _("Mixer Strip"),
3777                         &_mixer_strip_visibility,
3778                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_mixer_strip_visibility),
3779                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_mixer_strip_visibility)
3780                         )
3781                 );
3782
3783         add_option (_("Appearance/Mixer"),
3784              new BoolOption (
3785                      "default-narrow_ms",
3786                      _("Use narrow strips in the mixer for new strips by default"),
3787                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_default_narrow_ms),
3788                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_default_narrow_ms)
3789                      ));
3790
3791         add_option (_("Appearance/Mixer"), new OptionEditorBlank ());
3792
3793         add_option (_("Appearance/Toolbar"), new OptionEditorHeading (_("Main Transport Toolbar Items")));
3794
3795         add_option (_("Appearance/Toolbar"),
3796              new BoolOption (
3797                      "show-toolbar-recpunch",
3798                      _("Display Record/Punch Options"),
3799                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_toolbar_recpunch),
3800                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_toolbar_recpunch)
3801                      ));
3802
3803         add_option (_("Appearance/Toolbar"),
3804              new BoolOption (
3805                      "show-toolbar-monitoring",
3806                      _("Display Monitor Options"),
3807                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_toolbar_monitoring),
3808                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_toolbar_monitoring)
3809                      ));
3810
3811         add_option (_("Appearance/Toolbar"),
3812              new BoolOption (
3813                      "show-toolbar-selclock",
3814                      _("Display Selection Clock"),
3815                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_toolbar_selclock),
3816                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_toolbar_selclock)
3817                      ));
3818
3819         if (!ARDOUR::Profile->get_small_screen()) {
3820                 add_option (_("Appearance/Toolbar"),
3821                                 new BoolOption (
3822                                         "show-secondary-clock",
3823                                         _("Display Secondary Clock"),
3824                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_secondary_clock),
3825                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_secondary_clock)
3826                                         ));
3827         }
3828
3829         add_option (_("Appearance/Toolbar"),
3830              new BoolOption (
3831                      "show-mini-timeline",
3832                      _("Display Navigation Timeline"),
3833                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_mini_timeline),
3834                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_mini_timeline)
3835                      ));
3836
3837         add_option (_("Appearance/Toolbar"),
3838              new BoolOption (
3839                      "show-editor-meter",
3840                      _("Display Master Level Meter"),
3841                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_editor_meter),
3842                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_editor_meter)
3843                      ));
3844
3845         add_option (_("Appearance/Toolbar"),
3846                         new ColumVisibilityOption (
3847                                 "action-table-columns", _("Display Action-Buttons"), 4,
3848                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_action_table_columns),
3849                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_action_table_columns)
3850                                 )
3851                         );
3852         add_option (_("Appearance/Toolbar"), new OptionEditorBlank ());
3853
3854
3855         /* and now the theme manager */
3856
3857         add_option (_("Appearance/Theme"), new OptionEditorHeading (_("Theme")));
3858
3859         add_option (_("Appearance/Theme"), new BoolOption (
3860                                 "flat-buttons",
3861                                 _("Draw \"flat\" buttons"),
3862                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_flat_buttons),
3863                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_flat_buttons)
3864                                 ));
3865
3866         add_option (_("Appearance/Theme"), new BoolOption (
3867                                 "boxy-buttons",
3868                                 _("Draw \"boxy\" buttons"),
3869                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_boxy_buttons),
3870                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_boxy_buttons)
3871                                 ));
3872
3873         add_option (_("Appearance/Theme"), new BoolOption (
3874                                 "meter-style-led",
3875                                 _("LED meter style"),
3876                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_style_led),
3877                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_style_led)
3878                                 ));
3879
3880
3881         HSliderOption *gui_hs = new HSliderOption(
3882                         "timeline-item-gradient-depth",
3883                         _("Waveforms color gradient depth"),
3884                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_gradient_depth),
3885                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_gradient_depth),
3886                         0, 1.0, 0.05
3887                         );
3888         gui_hs->scale().set_update_policy (Gtk::UPDATE_DELAYED);
3889         add_option (_("Appearance/Theme"), gui_hs);
3890
3891         gui_hs = new HSliderOption(
3892                         "timeline-item-gradient-depth",
3893                         _("Timeline item gradient depth"),
3894                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_timeline_item_gradient_depth),
3895                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_timeline_item_gradient_depth),
3896                         0, 1.0, 0.05
3897                         );
3898         gui_hs->scale().set_update_policy (Gtk::UPDATE_DELAYED);
3899         add_option (_("Appearance/Theme"), gui_hs);
3900
3901         vector<string> icon_sets = ::get_icon_sets ();
3902         if (icon_sets.size() > 1) {
3903                 ComboOption<std::string>* io = new ComboOption<std::string> (
3904                                 "icon-set", _("Icon Set"),
3905                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_icon_set),
3906                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_icon_set)
3907                                 );
3908                 for (vector<string>::const_iterator i = icon_sets.begin (); i != icon_sets.end (); ++i) {
3909                         io->add (*i, *i);
3910                 }
3911                 add_option (_("Appearance/Theme"), io);
3912         }
3913
3914         add_option (_("Appearance/Colors"), new OptionEditorHeading (_("Colors")));
3915         add_option (_("Appearance/Colors"), new ColorThemeManager);
3916         add_option (_("Appearance/Colors"), new OptionEditorBlank ());
3917
3918         /* Quirks */
3919
3920         OptionEditorHeading* quirks_head = new OptionEditorHeading (_("Various Workarounds for Windowing Systems"));
3921
3922         quirks_head->set_note (string_compose (_("Rules for closing, minimizing, maximizing, and stay-on-top can vary \
3923 with each version of your OS, and the preferences that you've set in your OS.\n\n\
3924 You can adjust the options, below, to change how %1's windows and dialogs behave.\n\n\
3925 These settings will only take effect after %1 is restarted.\n\
3926         "), PROGRAM_NAME));
3927
3928         add_option (_("Appearance/Quirks"), quirks_head);
3929
3930         bo = new BoolOption (
3931                      "use-wm-visibility",
3932                      _("Use visibility information provided by your Window Manager/Desktop"),
3933                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_wm_visibility),
3934                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_wm_visibility)
3935                      );
3936         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget (),
3937                                 _("If you have trouble toggling between hidden Editor and Mixer windows, try changing this setting."));
3938         add_option (_("Appearance/Quirks"), bo);
3939
3940 #ifndef __APPLE__
3941         bo = new BoolOption (
3942                         "all-floating-windows-are-dialogs",
3943                         _("All floating windows are dialogs"),
3944                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_all_floating_windows_are_dialogs),
3945                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_all_floating_windows_are_dialogs)
3946                         );
3947         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget (),
3948                         _("Mark all floating windows to be type \"Dialog\" rather than using \"Utility\" for some.\nThis may help with some window managers."));
3949         add_option (_("Appearance/Quirks"), bo);
3950
3951         bo = new BoolOption (
3952                         "transients-follow-front",
3953                         _("Transient windows follow front window."),
3954                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_transients_follow_front),
3955                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_transients_follow_front)
3956                         );
3957         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget (),
3958                                 _("Make transient windows follow the front window when toggling between the editor and mixer."));
3959         add_option (_("Appearance/Quirks"), bo);
3960 #endif
3961
3962         if (!Profile->get_mixbus()) {
3963                 bo = new BoolOption (
3964                                 "floating-monitor-section",
3965                                 _("Float detached monitor-section window"),
3966                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_floating_monitor_section),
3967                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_floating_monitor_section)
3968                                 );
3969                 Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget (),
3970                                         _("When detaching the monitoring section, mark it as \"Utility\" window to stay in front."));
3971                 add_option (_("Appearance/Quirks"), bo);
3972         }
3973
3974         add_option (_("Appearance/Quirks"), new OptionEditorBlank ());
3975
3976         /* VIDEO Timeline */
3977         add_option (_("Video"), new OptionEditorHeading (_("Video Server")));
3978         add_option (_("Video"), new VideoTimelineOptions (_rc_config));
3979
3980         Widget::show_all ();
3981
3982         //trigger some parameter-changed messages which affect widget-visibility or -sensitivity
3983         parameter_changed ("send-ltc");
3984         parameter_changed ("sync-source");
3985         parameter_changed ("use-monitor-bus");
3986         parameter_changed ("open-gui-after-adding-plugin");
3987
3988         XMLNode* node = ARDOUR_UI::instance()->preferences_settings();
3989         if (node) {
3990                 /* gcc4 complains about ambiguity with Gtk::Widget::set_state
3991                    (Gtk::StateType) here !!!
3992                 */
3993                 Tabbable::set_state (*node, Stateful::loading_state_version);
3994         }
3995
3996         set_current_page (_("General"));
3997 }
3998
3999 void
4000 RCOptionEditor::set_session (Session *s)
4001 {
4002         SessionHandlePtr::set_session (s);
4003         _transport_masters_widget.set_session (s);
4004 }
4005
4006 void
4007 RCOptionEditor::parameter_changed (string const & p)
4008 {
4009         OptionEditor::parameter_changed (p);
4010
4011         if (p == "use-monitor-bus") {
4012                 bool const s = Config->get_use_monitor_bus ();
4013                 if (!s) {
4014                         /* we can't use this if we don't have a monitor bus */
4015                         Config->set_solo_control_is_listen_control (false);
4016                 }
4017                 _solo_control_is_listen_control->set_sensitive (s);
4018                 _listen_position->set_sensitive (s);
4019         } else if (p == "sync-source") {
4020                 boost::shared_ptr<TransportMaster> tm (TransportMasterManager::instance().current());
4021                 if (boost::dynamic_pointer_cast<TimecodeTransportMaster> (tm)) {
4022                         _sync_framerate->set_sensitive (true);
4023                 } else {
4024                         _sync_framerate->set_sensitive (false);
4025                 }
4026         } else if (p == "send-ltc") {
4027                 bool const s = Config->get_send_ltc ();
4028                 _ltc_send_continuously->set_sensitive (s);
4029                 _ltc_volume_slider->set_sensitive (s);
4030         } else if (p == "open-gui-after-adding-plugin" || p == "show-inline-display-by-default") {
4031 #if (defined LV2_SUPPORT && defined LV2_EXTENDED)
4032                 _plugin_prefer_inline->set_sensitive (UIConfiguration::instance().get_open_gui_after_adding_plugin() && UIConfiguration::instance().get_show_inline_display_by_default());
4033 #endif
4034         }
4035 }
4036
4037 void RCOptionEditor::plugin_scan_refresh () {
4038         PluginManager::instance().refresh();
4039 }
4040
4041 void RCOptionEditor::clear_vst_cache () {
4042         PluginManager::instance().clear_vst_cache();
4043 }
4044
4045 void RCOptionEditor::clear_vst_blacklist () {
4046         PluginManager::instance().clear_vst_blacklist();
4047 }
4048
4049 void RCOptionEditor::clear_au_cache () {
4050         PluginManager::instance().clear_au_cache();
4051 }
4052
4053 void RCOptionEditor::clear_au_blacklist () {
4054         PluginManager::instance().clear_au_blacklist();
4055 }
4056
4057 void RCOptionEditor::edit_lxvst_path () {
4058         Glib::RefPtr<Gdk::Window> win = get_parent_window ();
4059         PathsDialog *pd = new PathsDialog (
4060                 *current_toplevel(), _("Set Linux VST Search Path"),
4061                 _rc_config->get_plugin_path_lxvst(),
4062                 PluginManager::instance().get_default_lxvst_path()
4063                 );
4064         ResponseType r = (ResponseType) pd->run ();
4065         pd->hide();
4066         if (r == RESPONSE_ACCEPT) {
4067                 _rc_config->set_plugin_path_lxvst(pd->get_serialized_paths());
4068
4069                 MessageDialog msg (_("Re-scan Plugins now?"),
4070                                 false /*no markup*/, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, true /*modal*/);
4071                 msg.set_default_response (Gtk::RESPONSE_YES);
4072                 if (msg.run() == Gtk::RESPONSE_YES) {
4073                         msg.hide ();
4074                         plugin_scan_refresh ();
4075                 }
4076         }
4077         delete pd;
4078 }
4079
4080 void RCOptionEditor::edit_vst_path () {
4081         PathsDialog *pd = new PathsDialog (
4082                 *current_toplevel(), _("Set Windows VST Search Path"),
4083                 _rc_config->get_plugin_path_vst(),
4084                 PluginManager::instance().get_default_windows_vst_path()
4085                 );
4086         ResponseType r = (ResponseType) pd->run ();
4087         pd->hide();
4088         if (r == RESPONSE_ACCEPT) {
4089                 _rc_config->set_plugin_path_vst(pd->get_serialized_paths());
4090                 MessageDialog msg (_("Re-scan Plugins now?"),
4091                                 false /*no markup*/, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, true /*modal*/);
4092                 msg.set_default_response (Gtk::RESPONSE_YES);
4093                 if (msg.run() == Gtk::RESPONSE_YES) {
4094                         msg.hide ();
4095                         plugin_scan_refresh ();
4096                 }
4097         }
4098         delete pd;
4099 }
4100
4101 Gtk::Window*
4102 RCOptionEditor::use_own_window (bool and_fill_it)
4103 {
4104         bool new_window = !own_window ();
4105
4106         Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
4107
4108         if (win && new_window) {
4109                 win->set_name ("PreferencesWindow");
4110                 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Preferences"), this);
4111                 win->resize (1, 1);
4112                 win->set_resizable (false);
4113         }
4114
4115         return win;
4116 }
4117
4118 XMLNode&
4119 RCOptionEditor::get_state ()
4120 {
4121         XMLNode* node = new XMLNode (X_("Preferences"));
4122         node->add_child_nocopy (Tabbable::get_state());
4123         return *node;
4124 }