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