Fix some typos (closes GH PR #356)
[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] = 0 != (*i)->protocol;
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] = 0 != cpi->protocol;
1395                                         _ignore_view_change--;
1396                                         selection_changed (); // update sensitivity
1397                                         break;
1398                                 }
1399                         }
1400                 }
1401
1402                 void selection_changed ()
1403                 {
1404                         //enable the Edit button when a row is selected for editing
1405                         TreeModel::Row row = *(_view.get_selection()->get_selected());
1406                         if (row && row[_model.enabled])
1407                                 edit_button->set_sensitive (true);
1408                         else
1409                                 edit_button->set_sensitive (false);
1410                 }
1411
1412                 void view_changed (TreeModel::Path const &, TreeModel::iterator const & i)
1413                 {
1414                         TreeModel::Row r = *i;
1415
1416                         if (_ignore_view_change) {
1417                                 return;
1418                         }
1419
1420                         ControlProtocolInfo* cpi = r[_model.protocol_info];
1421                         if (!cpi) {
1422                                 return;
1423                         }
1424
1425                         bool const was_enabled = (cpi->protocol != 0);
1426                         bool const is_enabled = r[_model.enabled];
1427
1428
1429                         if (was_enabled != is_enabled) {
1430
1431                                 if (!was_enabled) {
1432                                         ControlProtocolManager::instance().activate (*cpi);
1433                                 } else {
1434                                         ControlProtocolManager::instance().deactivate (*cpi);
1435                                 }
1436                         }
1437
1438                         selection_changed ();
1439                 }
1440
1441                 void edit_btn_clicked ()
1442                 {
1443                         std::string name;
1444                         ControlProtocolInfo* cpi;
1445                         TreeModel::Row row;
1446
1447                         row = *(_view.get_selection()->get_selected());
1448                         if (!row[_model.enabled]) {
1449                                 return;
1450                         }
1451                         cpi = row[_model.protocol_info];
1452                         if (!cpi || !cpi->protocol || !cpi->protocol->has_editor ()) {
1453                                 return;
1454                         }
1455                         Box* box = (Box*) cpi->protocol->get_gui ();
1456                         if (!box) {
1457                                 return;
1458                         }
1459                         if (box->get_parent()) {
1460                                 static_cast<ArdourWindow*>(box->get_parent())->present();
1461                                 return;
1462                         }
1463                         WindowTitle title (Glib::get_application_name());
1464                         title += row[_model.name];
1465                         title += _("Configuration");
1466                         /* once created, the window is managed by the surface itself (as ->get_parent())
1467                          * Surface's tear_down_gui() is called on session close, when de-activating
1468                          * or re-initializing a surface.
1469                          * tear_down_gui() hides an deletes the Window if it exists.
1470                          */
1471                         ArdourWindow* win = new ArdourWindow (*((Gtk::Window*) _view.get_toplevel()), title.get_string());
1472                         win->set_title (_("Control Protocol Settings"));
1473                         win->add (*box);
1474                         box->show ();
1475                         win->present ();
1476                 }
1477
1478                 void edit_clicked (GdkEventButton* ev)
1479                 {
1480                         if (ev->type != GDK_2BUTTON_PRESS) {
1481                                 return;
1482                         }
1483
1484                         edit_btn_clicked();
1485                 }
1486
1487                 class ControlSurfacesModelColumns : public TreeModelColumnRecord
1488         {
1489                 public:
1490
1491                         ControlSurfacesModelColumns ()
1492                         {
1493                                 add (name);
1494                                 add (enabled);
1495                                 add (protocol_info);
1496                         }
1497
1498                         TreeModelColumn<string> name;
1499                         TreeModelColumn<bool> enabled;
1500                         TreeModelColumn<ControlProtocolInfo*> protocol_info;
1501         };
1502
1503                 Glib::RefPtr<ListStore> _store;
1504                 ControlSurfacesModelColumns _model;
1505                 TreeView _view;
1506                 PBD::ScopedConnection protocol_status_connection;
1507                 uint32_t _ignore_view_change;
1508                 Gtk::Button* edit_button;
1509 };
1510
1511 class VideoTimelineOptions : public OptionEditorMiniPage
1512 {
1513         public:
1514                 VideoTimelineOptions (RCConfiguration* c)
1515                         : _rc_config (c)
1516                         , _show_video_export_info_button (_("Show Video Export Info before export"))
1517                         , _show_video_server_dialog_button (_("Show Video Server Startup Dialog"))
1518                         , _video_advanced_setup_button (_("Advanced Setup (remote video server)"))
1519                         , _xjadeo_browse_button (_("Browse..."))
1520                 {
1521                         Table* t = &table;
1522                         int n = table.property_n_rows();
1523
1524                         t->attach (_show_video_export_info_button, 1, 4, n, n + 1);
1525                         _show_video_export_info_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::show_video_export_info_toggled));
1526                         Gtkmm2ext::UI::instance()->set_tip (_show_video_export_info_button,
1527                                         _("<b>When enabled</b> an information window with details is displayed before the video-export dialog."));
1528                         ++n;
1529
1530                         t->attach (_show_video_server_dialog_button, 1, 4, n, n + 1);
1531                         _show_video_server_dialog_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::show_video_server_dialog_toggled));
1532                         Gtkmm2ext::UI::instance()->set_tip (_show_video_server_dialog_button,
1533                                         _("<b>When enabled</b> the video server is never launched automatically without confirmation"));
1534                         ++n;
1535
1536                         t->attach (_video_advanced_setup_button, 1, 4, n, n + 1, FILL);
1537                         _video_advanced_setup_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::video_advanced_setup_toggled));
1538                         Gtkmm2ext::UI::instance()->set_tip (_video_advanced_setup_button,
1539                                         _("<b>When enabled</b> you can specify a custom video-server URL and docroot. - Do not enable this option unless you know what you are doing."));
1540                         ++n;
1541
1542                         Label* l = manage (new Label (_("Video Server URL:")));
1543                         l->set_alignment (0, 0.5);
1544                         t->attach (*l, 1, 2, n, n + 1, FILL);
1545                         t->attach (_video_server_url_entry, 2, 4, n, n + 1, FILL);
1546                         Gtkmm2ext::UI::instance()->set_tip (_video_server_url_entry,
1547                                         _("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"));
1548                         ++n;
1549
1550                         l = manage (new Label (_("Video Folder:")));
1551                         l->set_alignment (0, 0.5);
1552                         t->attach (*l, 1, 2, n, n + 1, FILL);
1553                         t->attach (_video_server_docroot_entry, 2, 4, n, n + 1);
1554                         Gtkmm2ext::UI::instance()->set_tip (_video_server_docroot_entry,
1555                                         _("Local path to the video-server document-root. Only files below this directory will be accessible by the video-server. If the server run on a remote host, it should point to a network mounted folder of the server's docroot or be left empty if it is unavailable. It is used for the local video-monitor and file-browsing when opening/adding a video file."));
1556                         ++n;
1557
1558                         l = manage (new Label (""));
1559                         t->attach (*l, 0, 4, n, n + 1, EXPAND | FILL);
1560                         ++n;
1561
1562                         l = manage (new Label (string_compose ("<b>%1</b>", _("Video Monitor"))));
1563                         l->set_use_markup (true);
1564                         l->set_alignment (0, 0.5);
1565                         t->attach (*l, 0, 4, n, n + 1, EXPAND | FILL);
1566                         ++n;
1567
1568                         l = manage (new Label (string_compose (_("Custom Path to Video Monitor (%1) - leave empty for default:"),
1569 #ifdef __APPLE__
1570                                                         "Jadeo.app"
1571 #elif defined PLATFORM_WINDOWS
1572                                                         "xjadeo.exe"
1573 #else
1574                                                         "xjadeo"
1575 #endif
1576                                                         )));
1577                         l->set_alignment (0, 0.5);
1578                         t->attach (*l, 1, 4, n, n + 1, FILL);
1579                         ++n;
1580
1581                         t->attach (_custom_xjadeo_path, 2, 3, n, n + 1, EXPAND|FILL);
1582                         Gtkmm2ext::UI::instance()->set_tip (_custom_xjadeo_path, _("Set a custom path to the Video Monitor Executable, changing this requires a restart."));
1583                         t->attach (_xjadeo_browse_button, 3, 4, n, n + 1, FILL);
1584
1585                         _video_server_url_entry.signal_changed().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_url_changed));
1586                         _video_server_url_entry.signal_activate().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_url_changed));
1587                         _video_server_docroot_entry.signal_changed().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_docroot_changed));
1588                         _video_server_docroot_entry.signal_activate().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_docroot_changed));
1589                         _custom_xjadeo_path.signal_changed().connect (sigc::mem_fun (*this, &VideoTimelineOptions::custom_xjadeo_path_changed));
1590                         _xjadeo_browse_button.signal_clicked ().connect (sigc::mem_fun (*this, &VideoTimelineOptions::xjadeo_browse_clicked));
1591
1592                         // xjadeo-path is a UIConfig parameter
1593                         UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &VideoTimelineOptions::parameter_changed));
1594                 }
1595
1596                 void server_url_changed ()
1597                 {
1598                         _rc_config->set_video_server_url (_video_server_url_entry.get_text());
1599                 }
1600
1601                 void server_docroot_changed ()
1602                 {
1603                         _rc_config->set_video_server_docroot (_video_server_docroot_entry.get_text());
1604                 }
1605
1606                 void show_video_export_info_toggled ()
1607                 {
1608                         bool const x = _show_video_export_info_button.get_active ();
1609                         _rc_config->set_show_video_export_info (x);
1610                 }
1611
1612                 void show_video_server_dialog_toggled ()
1613                 {
1614                         bool const x = _show_video_server_dialog_button.get_active ();
1615                         _rc_config->set_show_video_server_dialog (x);
1616                 }
1617
1618                 void video_advanced_setup_toggled ()
1619                 {
1620                         bool const x = _video_advanced_setup_button.get_active ();
1621                         _rc_config->set_video_advanced_setup(x);
1622                 }
1623
1624                 void custom_xjadeo_path_changed ()
1625                 {
1626                         UIConfiguration::instance().set_xjadeo_binary (_custom_xjadeo_path.get_text());
1627                 }
1628
1629                 void xjadeo_browse_clicked ()
1630                 {
1631                         Gtk::FileChooserDialog dialog(_("Set Video Monitor Executable"), Gtk::FILE_CHOOSER_ACTION_OPEN);
1632                         dialog.set_filename (UIConfiguration::instance().get_xjadeo_binary());
1633                         dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1634                         dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
1635                         if (dialog.run () == Gtk::RESPONSE_OK) {
1636                                 const std::string& filename = dialog.get_filename();
1637                                 if (!filename.empty() && (
1638 #ifdef __APPLE__
1639                                                         Glib::file_test (filename + "/Contents/MacOS/xjadeo", Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE) ||
1640 #endif
1641                                                         Glib::file_test (filename, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_EXECUTABLE)
1642                                                         )) {
1643                                         UIConfiguration::instance().set_xjadeo_binary (filename);
1644                                 }
1645                         }
1646                 }
1647
1648                 void parameter_changed (string const & p)
1649                 {
1650                         if (p == "video-server-url") {
1651                                 _video_server_url_entry.set_text (_rc_config->get_video_server_url());
1652                         } else if (p == "video-server-docroot") {
1653                                 _video_server_docroot_entry.set_text (_rc_config->get_video_server_docroot());
1654                         } else if (p == "show-video-export-info") {
1655                                 bool const x = _rc_config->get_show_video_export_info();
1656                                 _show_video_export_info_button.set_active (x);
1657                         } else if (p == "show-video-server-dialog") {
1658                                 bool const x = _rc_config->get_show_video_server_dialog();
1659                                 _show_video_server_dialog_button.set_active (x);
1660                         } else if (p == "video-advanced-setup") {
1661                                 bool const x = _rc_config->get_video_advanced_setup();
1662                                 _video_advanced_setup_button.set_active(x);
1663                                 _video_server_docroot_entry.set_sensitive(x);
1664                                 _video_server_url_entry.set_sensitive(x);
1665                         } else if (p == "xjadeo-binary") {
1666                                 _custom_xjadeo_path.set_text (UIConfiguration::instance().get_xjadeo_binary());
1667                         }
1668                 }
1669
1670                 void set_state_from_config ()
1671                 {
1672                         parameter_changed ("video-server-url");
1673                         parameter_changed ("video-server-docroot");
1674                         parameter_changed ("video-monitor-setup-dialog");
1675                         parameter_changed ("show-video-export-info");
1676                         parameter_changed ("show-video-server-dialog");
1677                         parameter_changed ("video-advanced-setup");
1678                         parameter_changed ("xjadeo-binary");
1679                 }
1680
1681         private:
1682                 RCConfiguration* _rc_config;
1683                 Entry _video_server_url_entry;
1684                 Entry _video_server_docroot_entry;
1685                 Entry _custom_xjadeo_path;
1686                 CheckButton _show_video_export_info_button;
1687                 CheckButton _show_video_server_dialog_button;
1688                 CheckButton _video_advanced_setup_button;
1689                 Button _xjadeo_browse_button;
1690 };
1691
1692 class ColumVisibilityOption : public Option
1693 {
1694         public:
1695         ColumVisibilityOption (string id, string name, uint32_t n_col, sigc::slot<uint32_t> get, sigc::slot<bool, uint32_t> set)
1696                 : Option (id, name)
1697                 , _heading (name)
1698                 , _n_col (n_col)
1699                 , _get (get)
1700                 , _set (set)
1701         {
1702                 cb = (CheckButton**) malloc (sizeof (CheckButton*) * n_col);
1703                 for (uint32_t i = 0; i < n_col; ++i) {
1704                         CheckButton* col = manage (new CheckButton (string_compose (_("Column %1"), i + 1)));
1705                         col->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &ColumVisibilityOption::column_toggled), i));
1706                         _hbox.pack_start (*col);
1707                         cb[i] = col;
1708                 }
1709                 parameter_changed (id);
1710         }
1711
1712         ~ColumVisibilityOption () {
1713                 free (cb);
1714         }
1715
1716         Gtk::Widget& tip_widget() { return _hbox; }
1717
1718         void set_state_from_config ()
1719         {
1720                 uint32_t c = _get();
1721                 for (uint32_t i = 0; i < _n_col; ++i) {
1722                         bool en = (c & (1<<i)) ? true : false;
1723                         if (cb[i]->get_active () != en) {
1724                                 cb[i]->set_active (en);
1725                         }
1726                 }
1727         }
1728
1729         void add_to_page (OptionEditorPage* p)
1730         {
1731                 _heading.add_to_page (p);
1732                 add_widget_to_page (p, &_hbox);
1733         }
1734         private:
1735
1736         void column_toggled (int b) {
1737                 uint32_t c = _get();
1738                 uint32_t cc = c;
1739                 if (cb[b]->get_active ()) {
1740                         c |= (1<<b);
1741                 } else {
1742                         c &= ~(1<<b);
1743                 }
1744                 if (cc != c) {
1745                         _set (c);
1746                 }
1747         }
1748
1749         HBox _hbox;
1750         OptionEditorHeading _heading;
1751
1752         CheckButton** cb;
1753         uint32_t _n_col;
1754         sigc::slot<uint32_t> _get;
1755         sigc::slot<bool, uint32_t> _set;
1756 };
1757
1758
1759 /** A class which allows control of visibility of some editor components usign
1760  *  a VisibilityGroup.  The caller should pass in a `dummy' VisibilityGroup
1761  *  which has the correct members, but with null widget pointers.  This
1762  *  class allows the user to set visibility of the members, the details
1763  *  of which are stored in a configuration variable which can be watched
1764  *  by parts of the editor that actually contain the widgets whose visibility
1765  *  is being controlled.
1766  */
1767
1768 class VisibilityOption : public Option
1769 {
1770 public:
1771         /** @param name User-visible name for this group.
1772          *  @param g `Dummy' VisibilityGroup (as described above).
1773          *  @param get Method to get the value of the appropriate configuration variable.
1774          *  @param set Method to set the value of the appropriate configuration variable.
1775          */
1776         VisibilityOption (string name, VisibilityGroup* g, sigc::slot<string> get, sigc::slot<bool, string> set)
1777                 : Option (g->get_state_name(), name)
1778                 , _heading (name)
1779                 , _visibility_group (g)
1780                 , _get (get)
1781                 , _set (set)
1782         {
1783                 /* Watch for changes made by the user to our members */
1784                 _visibility_group->VisibilityChanged.connect_same_thread (
1785                         _visibility_group_connection, sigc::bind (&VisibilityOption::changed, this)
1786                         );
1787         }
1788
1789         void set_state_from_config ()
1790         {
1791                 /* Set our state from the current configuration */
1792                 _visibility_group->set_state (_get ());
1793         }
1794
1795         void add_to_page (OptionEditorPage* p)
1796         {
1797                 _heading.add_to_page (p);
1798                 add_widget_to_page (p, _visibility_group->list_view ());
1799         }
1800
1801         Gtk::Widget& tip_widget() { return *_visibility_group->list_view (); }
1802
1803 private:
1804         void changed ()
1805         {
1806                 /* The user has changed something, so reflect this change
1807                    in the RCConfiguration.
1808                 */
1809                 _set (_visibility_group->get_state_value ());
1810         }
1811
1812         OptionEditorHeading _heading;
1813         VisibilityGroup* _visibility_group;
1814         sigc::slot<std::string> _get;
1815         sigc::slot<bool, std::string> _set;
1816         PBD::ScopedConnection _visibility_group_connection;
1817 };
1818
1819
1820 class MidiPortOptions : public OptionEditorMiniPage, public sigc::trackable
1821 {
1822         public:
1823                 MidiPortOptions() {
1824
1825                         setup_midi_port_view (midi_output_view, false);
1826                         setup_midi_port_view (midi_input_view, true);
1827
1828                         OptionEditorHeading* h = new OptionEditorHeading (_("MIDI Inputs"));
1829                         h->add_to_page (this);
1830
1831                         Gtk::ScrolledWindow* scroller = manage (new Gtk::ScrolledWindow);
1832                         scroller->add (midi_input_view);
1833                         scroller->set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
1834                         scroller->set_size_request (-1, 180);
1835
1836                         int n = table.property_n_rows();
1837                         table.attach (*scroller, 0, 3, n, n + 1, FILL | EXPAND);
1838
1839                         h = new OptionEditorHeading (_("MIDI Outputs"));
1840                         h->add_to_page (this);
1841
1842                         scroller = manage (new Gtk::ScrolledWindow);
1843                         scroller->add (midi_output_view);
1844                         scroller->set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
1845                         scroller->set_size_request (-1, 180);
1846
1847                         n = table.property_n_rows();
1848                         table.attach (*scroller, 0, 3, n, n + 1, FILL | EXPAND);
1849
1850                         midi_output_view.show ();
1851                         midi_input_view.show ();
1852
1853                         table.signal_show().connect (sigc::mem_fun (*this, &MidiPortOptions::on_show));
1854                 }
1855
1856                 void parameter_changed (string const&) {}
1857                 void set_state_from_config() {}
1858
1859                 void on_show () {
1860                         refill ();
1861
1862                         AudioEngine::instance()->PortRegisteredOrUnregistered.connect (connections,
1863                                         invalidator (*this),
1864                                         boost::bind (&MidiPortOptions::refill, this),
1865                                         gui_context());
1866                         AudioEngine::instance()->MidiPortInfoChanged.connect (connections,
1867                                         invalidator (*this),
1868                                         boost::bind (&MidiPortOptions::refill, this),
1869                                         gui_context());
1870                         AudioEngine::instance()->MidiSelectionPortsChanged.connect (connections,
1871                                         invalidator (*this),
1872                                         boost::bind (&MidiPortOptions::refill, this),
1873                                         gui_context());
1874                 }
1875
1876                 void refill () {
1877
1878                         if (refill_midi_ports (true, midi_input_view)) {
1879                                 input_label.show ();
1880                         } else {
1881                                 input_label.hide ();
1882                         }
1883                         if (refill_midi_ports (false, midi_output_view)) {
1884                                 output_label.show ();
1885                         } else {
1886                                 output_label.hide ();
1887                         }
1888                 }
1889
1890         private:
1891                 PBD::ScopedConnectionList connections;
1892
1893                 /* MIDI port management */
1894                 struct MidiPortColumns : public Gtk::TreeModel::ColumnRecord {
1895
1896                         MidiPortColumns () {
1897                                 add (pretty_name);
1898                                 add (music_data);
1899                                 add (control_data);
1900                                 add (selection);
1901                                 add (name);
1902                                 add (filler);
1903                         }
1904
1905                         Gtk::TreeModelColumn<std::string> pretty_name;
1906                         Gtk::TreeModelColumn<bool> music_data;
1907                         Gtk::TreeModelColumn<bool> control_data;
1908                         Gtk::TreeModelColumn<bool> selection;
1909                         Gtk::TreeModelColumn<std::string> name;
1910                         Gtk::TreeModelColumn<std::string> filler;
1911                 };
1912
1913                 MidiPortColumns midi_port_columns;
1914                 Gtk::TreeView midi_input_view;
1915                 Gtk::TreeView midi_output_view;
1916                 Gtk::Label input_label;
1917                 Gtk::Label output_label;
1918
1919                 void setup_midi_port_view (Gtk::TreeView&, bool with_selection);
1920                 bool refill_midi_ports (bool for_input, Gtk::TreeView&);
1921                 void pretty_name_edit (std::string const & path, std::string const & new_text, Gtk::TreeView*);
1922                 void midi_music_column_toggled (std::string const & path, Gtk::TreeView*);
1923                 void midi_control_column_toggled (std::string const & path, Gtk::TreeView*);
1924                 void midi_selection_column_toggled (std::string const & path, Gtk::TreeView*);
1925 };
1926
1927 void
1928 MidiPortOptions::setup_midi_port_view (Gtk::TreeView& view, bool with_selection)
1929 {
1930         int pretty_name_column;
1931         int music_column;
1932         int control_column;
1933         int selection_column;
1934         TreeViewColumn* col;
1935         Gtk::Label* l;
1936
1937         pretty_name_column = view.append_column_editable (_("Name (click to edit)"), midi_port_columns.pretty_name) - 1;
1938
1939         col = manage (new TreeViewColumn ("", midi_port_columns.music_data));
1940         col->set_alignment (ALIGN_CENTER);
1941         l = manage (new Label (_("Music Data")));
1942         set_tooltip (*l, string_compose (_("If ticked, %1 will consider this port to be a source of music performance data."), PROGRAM_NAME));
1943         col->set_widget (*l);
1944         l->show ();
1945         music_column = view.append_column (*col) - 1;
1946
1947         col = manage (new TreeViewColumn ("", midi_port_columns.control_data));
1948         col->set_alignment (ALIGN_CENTER);
1949         l = manage (new Label (_("Control Data")));
1950         set_tooltip (*l, string_compose (_("If ticked, %1 will consider this port to be a source of control data."), PROGRAM_NAME));
1951         col->set_widget (*l);
1952         l->show ();
1953         control_column = view.append_column (*col) - 1;
1954
1955         if (with_selection) {
1956                 col = manage (new TreeViewColumn (_("Follow Selection"), midi_port_columns.selection));
1957                 selection_column = view.append_column (*col) - 1;
1958                 l = manage (new Label (_("Follow Selection")));
1959                 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));
1960                 col->set_widget (*l);
1961                 l->show ();
1962         }
1963
1964         /* filler column so that the last real column doesn't expand */
1965         view.append_column ("", midi_port_columns.filler);
1966
1967         CellRendererText* pretty_name_cell = dynamic_cast<CellRendererText*> (view.get_column_cell_renderer (pretty_name_column));
1968         pretty_name_cell->property_editable() = true;
1969         pretty_name_cell->signal_edited().connect (sigc::bind (sigc::mem_fun (*this, &MidiPortOptions::pretty_name_edit), &view));
1970
1971         CellRendererToggle* toggle_cell;
1972
1973         toggle_cell = dynamic_cast<CellRendererToggle*> (view.get_column_cell_renderer (music_column));
1974         toggle_cell->property_activatable() = true;
1975         toggle_cell->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiPortOptions::midi_music_column_toggled), &view));
1976
1977         toggle_cell = dynamic_cast<CellRendererToggle*> (view.get_column_cell_renderer (control_column));
1978         toggle_cell->property_activatable() = true;
1979         toggle_cell->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiPortOptions::midi_control_column_toggled), &view));
1980
1981         if (with_selection) {
1982                 toggle_cell = dynamic_cast<CellRendererToggle*> (view.get_column_cell_renderer (selection_column));
1983                 toggle_cell->property_activatable() = true;
1984                 toggle_cell->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MidiPortOptions::midi_selection_column_toggled), &view));
1985         }
1986
1987         view.get_selection()->set_mode (SELECTION_NONE);
1988         view.set_tooltip_column (4); /* port "real" name */
1989         view.get_column(0)->set_resizable (true);
1990         view.get_column(0)->set_expand (true);
1991 }
1992
1993 bool
1994 MidiPortOptions::refill_midi_ports (bool for_input, Gtk::TreeView& view)
1995 {
1996         using namespace ARDOUR;
1997
1998         std::vector<string> ports;
1999
2000         AudioEngine::instance()->get_known_midi_ports (ports);
2001
2002         if (ports.empty()) {
2003                 view.hide ();
2004                 return false;
2005         }
2006
2007         Glib::RefPtr<ListStore> model = Gtk::ListStore::create (midi_port_columns);
2008
2009         for (vector<string>::const_iterator s = ports.begin(); s != ports.end(); ++s) {
2010
2011                 if (AudioEngine::instance()->port_is_mine (*s)) {
2012                         continue;
2013                 }
2014
2015                 PortManager::MidiPortInformation mpi (AudioEngine::instance()->midi_port_information (*s));
2016
2017                 if (mpi.pretty_name.empty()) {
2018                         /* vanished since get_known_midi_ports() */
2019                         continue;
2020                 }
2021
2022                 if (for_input != mpi.input) {
2023                         continue;
2024                 }
2025
2026                 TreeModel::Row row = *(model->append());
2027
2028                 row[midi_port_columns.pretty_name] = mpi.pretty_name;
2029                 row[midi_port_columns.music_data] = mpi.properties & MidiPortMusic;
2030                 row[midi_port_columns.control_data] = mpi.properties & MidiPortControl;
2031                 row[midi_port_columns.selection] = mpi.properties & MidiPortSelection;
2032                 row[midi_port_columns.name] = *s;
2033         }
2034
2035         view.set_model (model);
2036
2037         return true;
2038 }
2039
2040 void
2041 MidiPortOptions::midi_music_column_toggled (string const & path, TreeView* view)
2042 {
2043         TreeIter iter = view->get_model()->get_iter (path);
2044
2045         if (!iter) {
2046                 return;
2047         }
2048
2049         bool new_value = ! bool ((*iter)[midi_port_columns.music_data]);
2050
2051         /* don't reset model - wait for MidiPortInfoChanged signal */
2052
2053         if (new_value) {
2054                 ARDOUR::AudioEngine::instance()->add_midi_port_flags ((*iter)[midi_port_columns.name], MidiPortMusic);
2055         } else {
2056                 ARDOUR::AudioEngine::instance()->remove_midi_port_flags ((*iter)[midi_port_columns.name], MidiPortMusic);
2057         }
2058 }
2059
2060 void
2061 MidiPortOptions::midi_control_column_toggled (string const & path, TreeView* view)
2062 {
2063         TreeIter iter = view->get_model()->get_iter (path);
2064
2065         if (!iter) {
2066                 return;
2067         }
2068
2069         bool new_value = ! bool ((*iter)[midi_port_columns.control_data]);
2070
2071         /* don't reset model - wait for MidiPortInfoChanged signal */
2072
2073         if (new_value) {
2074                 ARDOUR::AudioEngine::instance()->add_midi_port_flags ((*iter)[midi_port_columns.name], MidiPortControl);
2075         } else {
2076                 ARDOUR::AudioEngine::instance()->remove_midi_port_flags ((*iter)[midi_port_columns.name], MidiPortControl);
2077         }
2078 }
2079
2080 void
2081 MidiPortOptions::midi_selection_column_toggled (string const & path, TreeView* view)
2082 {
2083         TreeIter iter = view->get_model()->get_iter (path);
2084
2085         if (!iter) {
2086                 return;
2087         }
2088
2089         bool new_value = ! bool ((*iter)[midi_port_columns.selection]);
2090
2091         /* don't reset model - wait for MidiSelectionPortsChanged signal */
2092
2093         if (new_value) {
2094                 ARDOUR::AudioEngine::instance()->add_midi_port_flags ((*iter)[midi_port_columns.name], MidiPortSelection);
2095         } else {
2096                 ARDOUR::AudioEngine::instance()->remove_midi_port_flags ((*iter)[midi_port_columns.name], MidiPortSelection);
2097         }
2098 }
2099
2100 void
2101 MidiPortOptions::pretty_name_edit (std::string const & path, string const & new_text, Gtk::TreeView* view)
2102 {
2103         TreeIter iter = view->get_model()->get_iter (path);
2104
2105         if (!iter) {
2106                 return;
2107         }
2108
2109         boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend();
2110         if (backend) {
2111                 ARDOUR::PortEngine::PortHandle ph = backend->get_port_by_name ((*iter)[midi_port_columns.name]);
2112                 if (ph) {
2113                         backend->set_port_property (ph, "http://jackaudio.org/metadata/pretty-name", new_text, "");
2114                         (*iter)[midi_port_columns.pretty_name] = new_text;
2115                 }
2116         }
2117 }
2118
2119 /*============*/
2120
2121
2122 RCOptionEditor::RCOptionEditor ()
2123         : OptionEditorContainer (Config, string_compose (_("%1 Preferences"), PROGRAM_NAME))
2124         , Tabbable (*this, _("Preferences")
2125 #ifdef MIXBUS
2126                         , false // detached by default (first start, no instant.xml)
2127 #endif
2128                         ) /* pack self-as-vbox into tabbable */
2129         , _rc_config (Config)
2130         , _mixer_strip_visibility ("mixer-element-visibility")
2131 {
2132         UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &RCOptionEditor::parameter_changed));
2133
2134         /* MISC */
2135
2136         uint32_t hwcpus = hardware_concurrency ();
2137         BoolOption* bo;
2138         BoolComboOption* bco;
2139
2140         if (hwcpus > 1) {
2141                 add_option (_("General"), new OptionEditorHeading (_("DSP CPU Utilization")));
2142
2143                 ComboOption<int32_t>* procs = new ComboOption<int32_t> (
2144                                 "processor-usage",
2145                                 _("Signal processing uses"),
2146                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_processor_usage),
2147                                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_processor_usage)
2148                                 );
2149
2150                 procs->add (-1, _("all but one processor"));
2151                 procs->add (0, _("all available processors"));
2152
2153                 for (uint32_t i = 1; i <= hwcpus; ++i) {
2154                         procs->add (i, string_compose (P_("%1 processor", "%1 processors", i), i));
2155                 }
2156
2157                 procs->set_note (string_compose (_("This setting will only take effect when %1 is restarted."), PROGRAM_NAME));
2158
2159                 add_option (_("General"), procs);
2160         }
2161
2162         /* Image cache size */
2163         add_option (_("General"), new OptionEditorHeading (_("Memory Usage")));
2164
2165         HSliderOption *sics = new HSliderOption ("waveform-cache-size",
2166                         _("Waveform image cache size (megabytes)"),
2167                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_cache_size),
2168                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_cache_size),
2169                         1, 1024, 10 /* 1 MB to 1GB in steps of 10MB */
2170                         );
2171         sics->scale().set_digits (0);
2172         Gtkmm2ext::UI::instance()->set_tip (
2173                         sics->tip_widget(),
2174                  _("Increasing the cache size uses more memory to store waveform images, which can improve graphical performance."));
2175         add_option (_("General"), sics);
2176
2177         add_option (_("General"), new OptionEditorHeading (_("Engine")));
2178
2179         add_option (_("General"),
2180              new BoolOption (
2181                      "try-autostart-engine",
2182                      _("Try to auto-launch audio/midi engine"),
2183                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_try_autostart_engine),
2184                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_try_autostart_engine)
2185                      ));
2186
2187         add_option (_("General"), new OptionEditorHeading (_("Automation")));
2188
2189         add_option (_("General"),
2190              new SpinOption<double> (
2191                      "automation-thinning-factor",
2192                      _("Thinning factor (larger value => less data)"),
2193                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_thinning_factor),
2194                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_thinning_factor),
2195                      0, 1000, 1, 20
2196                      ));
2197
2198         add_option (_("General"),
2199              new SpinOption<double> (
2200                      "automation-interval-msecs",
2201                      _("Automation sampling interval (milliseconds)"),
2202                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_interval_msecs),
2203                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_interval_msecs),
2204                      1, 1000, 1, 20
2205                      ));
2206
2207         add_option (_("General"), new OptionEditorHeading (_("Tempo")));
2208
2209         bo = new BoolOption (
2210                 "allow-non-quarter-pulse",
2211                 _("Allow non quarter-note pulse"),
2212                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_allow_non_quarter_pulse),
2213                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_allow_non_quarter_pulse)
2214                 );
2215         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2216                                             string_compose (_("<b>When enabled</b> %1 will allow tempo to be expressed in divisions per minute\n"
2217                                                               "<b>When disabled</b> %1 will only allow tempo to be expressed in quarter notes per minute"),
2218                                                             PROGRAM_NAME));
2219         add_option (_("General"), bo);
2220
2221         if (!ARDOUR::Profile->get_mixbus()) {
2222                 add_option (_("General"), new OptionEditorHeading (_("GUI Lock")));
2223                 /* Lock GUI timeout */
2224
2225                 HSliderOption *slts = new HSliderOption("lock-gui-after-seconds",
2226                                 _("Lock timeout (seconds)"),
2227                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_lock_gui_after_seconds),
2228                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_lock_gui_after_seconds),
2229                                 0, 1000, 1, 10
2230                                 );
2231                 slts->scale().set_digits (0);
2232                 Gtkmm2ext::UI::instance()->set_tip (
2233                                 slts->tip_widget(),
2234                                 _("Lock GUI after this many idle seconds (zero to never lock)"));
2235                 add_option (_("General"), slts);
2236         } // !mixbus
2237
2238         add_option (_("General/Session"), new OptionEditorHeading (S_("Options|Undo")));
2239
2240         add_option (_("General/Session"), new UndoOptions (_rc_config));
2241
2242         add_option (_("General/Session"),
2243              new BoolOption (
2244                      "verify-remove-last-capture",
2245                      _("Verify removal of last capture"),
2246                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_verify_remove_last_capture),
2247                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_verify_remove_last_capture)
2248                      ));
2249
2250         add_option (_("General/Session"), new OptionEditorHeading (_("Session Management")));
2251
2252         add_option (_("General/Session"),
2253              new BoolOption (
2254                      "periodic-safety-backups",
2255                      _("Make periodic backups of the session file"),
2256                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_periodic_safety_backups),
2257                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_periodic_safety_backups)
2258                      ));
2259
2260         add_option (_("General/Session"),
2261              new BoolOption (
2262                      "only-copy-imported-files",
2263                      _("Always copy imported files"),
2264                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_only_copy_imported_files),
2265                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_only_copy_imported_files)
2266                      ));
2267
2268         add_option (_("General/Session"), new DirectoryOption (
2269                             X_("default-session-parent-dir"),
2270                             _("Default folder for new sessions:"),
2271                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_default_session_parent_dir),
2272                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_default_session_parent_dir)
2273                             ));
2274
2275         add_option (_("General/Session"),
2276              new SpinOption<uint32_t> (
2277                      "max-recent-sessions",
2278                      _("Maximum number of recent sessions"),
2279                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_max_recent_sessions),
2280                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_max_recent_sessions),
2281                      0, 1000, 1, 20
2282                      ));
2283
2284
2285 #ifdef ENABLE_NLS
2286
2287         add_option (_("General/Translation"), new OptionEditorHeading (_("Internationalization")));
2288
2289         bo = new BoolOption (
2290                         "enable-translation",
2291                         _("Use translations"),
2292                         sigc::ptr_fun (ARDOUR::translations_are_enabled),
2293                         sigc::ptr_fun (ARDOUR::set_translations_enabled)
2294                         );
2295
2296         bo->set_note (string_compose (_("These settings will only take effect after %1 is restarted (if available for your language preferences)."), PROGRAM_NAME));
2297
2298         add_option (_("General/Translation"), bo);
2299
2300         parameter_changed ("enable-translation");
2301 #endif // ENABLE_NLS
2302
2303
2304         /* EDITOR */
2305
2306         add_option (_("Editor"), new OptionEditorHeading (_("General")));
2307
2308         add_option (_("Editor"),
2309              new BoolOption (
2310                      "rubberbanding-snaps-to-grid",
2311                      _("Snap rubberband to grid"),
2312                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_rubberbanding_snaps_to_grid),
2313                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_rubberbanding_snaps_to_grid)
2314                      ));
2315
2316         bo = new BoolOption (
2317                      "name-new-markers",
2318                      _("Prompt for new marker names"),
2319                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_name_new_markers),
2320                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_name_new_markers)
2321                 );
2322         add_option (_("Editor"), bo);
2323         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."
2324                                                                 "\n\nYou can always rename markers by right-clicking on them"));
2325
2326         add_option (_("Editor"),
2327              new BoolOption (
2328                      "draggable-playhead",
2329                      _("Allow dragging of playhead"),
2330                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_draggable_playhead),
2331                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_draggable_playhead)
2332                      ));
2333
2334         if (!Profile->get_mixbus()) {
2335
2336                 add_option (_("Editor"),
2337                                 new BoolOption (
2338                                         "use-mouse-position-as-zoom-focus-on-scroll",
2339                                         _("Zoom to mouse position when zooming with scroll wheel"),
2340                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_mouse_position_as_zoom_focus_on_scroll),
2341                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_mouse_position_as_zoom_focus_on_scroll)
2342                                         ));
2343         }  // !mixbus
2344
2345         add_option (_("Editor"),
2346                     new BoolOption (
2347                             "use-time-rulers-to-zoom-with-vertical-drag",
2348                             _("Zoom with vertical drag in rulers"),
2349                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_time_rulers_to_zoom_with_vertical_drag),
2350                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_time_rulers_to_zoom_with_vertical_drag)
2351                             ));
2352
2353         add_option (_("Editor"),
2354                     new BoolOption (
2355                             "use-double-click-to-zoom-to-selection",
2356                             _("Double click zooms to selection"),
2357                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_double_click_to_zoom_to_selection),
2358                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_double_click_to_zoom_to_selection)
2359                             ));
2360
2361         add_option (_("Editor"),
2362                     new BoolOption (
2363                             "update-editor-during-summary-drag",
2364                             _("Update editor window during drags of the summary"),
2365                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_update_editor_during_summary_drag),
2366                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_update_editor_during_summary_drag)
2367                             ));
2368
2369         add_option (_("Editor"),
2370             new BoolOption (
2371                     "autoscroll-editor",
2372                     _("Auto-scroll editor window when dragging near its edges"),
2373                     sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_autoscroll_editor),
2374                     sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_autoscroll_editor)
2375                     ));
2376
2377         add_option (_("Editor"),
2378              new BoolComboOption (
2379                      "show-region-gain-envelopes",
2380                      _("Show gain envelopes in audio regions"),
2381                      _("in all modes"),
2382                      _("only in Draw and Internal Edit modes"),
2383                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_region_gain),
2384                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_region_gain)
2385                      ));
2386
2387         add_option (_("Editor"), new OptionEditorHeading (_("Editor Behavior")));
2388
2389         add_option (_("Editor"),
2390              new BoolOption (
2391                      "automation-follows-regions",
2392                      _("Move relevant automation when audio regions are moved"),
2393                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_follows_regions),
2394                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_follows_regions)
2395                      ));
2396
2397         bo = new BoolOption (
2398                      "new-automation-points-on-lane",
2399                      _("Ignore Y-axis click position when adding new automation-points"),
2400                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_new_automation_points_on_lane),
2401                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_new_automation_points_on_lane)
2402                      );
2403         add_option (_("Editor"), bo);
2404         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2405                         _("<b>When enabled</b> The new points drawn in any automation lane will be placed on the existing line, regardless of mouse y-axis position."));
2406
2407         ComboOption<FadeShape>* fadeshape = new ComboOption<FadeShape> (
2408                         "default-fade-shape",
2409                         _("Default fade shape"),
2410                         sigc::mem_fun (*_rc_config,
2411                                 &RCConfiguration::get_default_fade_shape),
2412                         sigc::mem_fun (*_rc_config,
2413                                 &RCConfiguration::set_default_fade_shape)
2414                         );
2415
2416         fadeshape->add (FadeLinear,
2417                         _("Linear (for highly correlated material)"));
2418         fadeshape->add (FadeConstantPower, _("Constant power"));
2419         fadeshape->add (FadeSymmetric, _("Symmetric"));
2420         fadeshape->add (FadeSlow, _("Slow"));
2421         fadeshape->add (FadeFast, _("Fast"));
2422
2423         add_option (_("Editor"), fadeshape);
2424
2425         bco = new BoolComboOption (
2426                      "use-overlap-equivalency",
2427                      _("Regions in edit groups are edited together"),
2428                      _("whenever they overlap in time"),
2429                      _("only if they have identical length and position"),
2430                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_use_overlap_equivalency),
2431                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_use_overlap_equivalency)
2432                      );
2433
2434         add_option (_("Editor"), bco);
2435
2436         ComboOption<LayerModel>* lm = new ComboOption<LayerModel> (
2437                 "layer-model",
2438                 _("Layering model"),
2439                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_layer_model),
2440                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_layer_model)
2441                 );
2442
2443         lm->add (LaterHigher, _("later is higher"));
2444         lm->add (Manual, _("manual layering"));
2445         add_option (_("Editor"), lm);
2446
2447         ComboOption<RegionSelectionAfterSplit> *rsas = new ComboOption<RegionSelectionAfterSplit> (
2448                     "region-selection-after-split",
2449                     _("After splitting selected regions, select"),
2450                     sigc::mem_fun (*_rc_config, &RCConfiguration::get_region_selection_after_split),
2451                     sigc::mem_fun (*_rc_config, &RCConfiguration::set_region_selection_after_split));
2452
2453         // TODO: decide which of these modes are really useful
2454         rsas->add(None, _("no regions"));
2455         // rsas->add(NewlyCreatedLeft, _("newly-created regions before the split"));
2456         // rsas->add(NewlyCreatedRight, _("newly-created regions after the split"));
2457         rsas->add(NewlyCreatedBoth, _("newly-created regions"));
2458         // rsas->add(Existing, _("unmodified regions in the existing selection"));
2459         // rsas->add(ExistingNewlyCreatedLeft, _("existing selection and newly-created regions before the split"));
2460         // rsas->add(ExistingNewlyCreatedRight, _("existing selection and newly-created regions after the split"));
2461         rsas->add(ExistingNewlyCreatedBoth, _("existing selection and newly-created regions"));
2462
2463         add_option (_("Editor"), rsas);
2464
2465         add_option (_("Editor/Modifiers"), new OptionEditorHeading (_("Keyboard Modifiers")));
2466         add_option (_("Editor/Modifiers"), new KeyboardOptions);
2467         add_option (_("Editor/Modifiers"), new OptionEditorBlank ());
2468
2469         /* MIXER -- SOLO AND MUTE */
2470
2471         add_option (_("Mixer"), new OptionEditorHeading (_("Solo")));
2472
2473         _solo_control_is_listen_control = new BoolOption (
2474                 "solo-control-is-listen-control",
2475                 _("Solo controls are Listen controls"),
2476                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_control_is_listen_control),
2477                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_control_is_listen_control)
2478                 );
2479
2480         add_option (_("Mixer"), _solo_control_is_listen_control);
2481
2482         add_option (_("Mixer"),
2483              new BoolOption (
2484                      "exclusive-solo",
2485                      _("Exclusive solo"),
2486                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_exclusive_solo),
2487                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_exclusive_solo)
2488                      ));
2489
2490         add_option (_("Mixer"),
2491              new BoolOption (
2492                      "show-solo-mutes",
2493                      _("Show solo muting"),
2494                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_show_solo_mutes),
2495                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_solo_mutes)
2496                      ));
2497
2498         add_option (_("Mixer"),
2499              new BoolOption (
2500                      "solo-mute-override",
2501                      _("Soloing overrides muting"),
2502                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_override),
2503                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_override)
2504                      ));
2505
2506         add_option (_("Mixer"),
2507              new FaderOption (
2508                      "solo-mute-gain",
2509                      _("Solo-in-place mute cut (dB)"),
2510                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_gain),
2511                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_gain)
2512                      ));
2513
2514         _listen_position = new ComboOption<ListenPosition> (
2515                 "listen-position",
2516                 _("Listen Position"),
2517                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_listen_position),
2518                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_listen_position)
2519                 );
2520
2521         _listen_position->add (AfterFaderListen, _("after-fader (AFL)"));
2522         _listen_position->add (PreFaderListen, _("pre-fader (PFL)"));
2523
2524         add_option (_("Mixer"), _listen_position);
2525
2526         ComboOption<PFLPosition>* pp = new ComboOption<PFLPosition> (
2527                 "pfl-position",
2528                 _("PFL signals come from"),
2529                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_pfl_position),
2530                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_pfl_position)
2531                 );
2532
2533         pp->add (PFLFromBeforeProcessors, _("before pre-fader processors"));
2534         pp->add (PFLFromAfterProcessors, _("pre-fader but after pre-fader processors"));
2535
2536         add_option (_("Mixer"), pp);
2537
2538         ComboOption<AFLPosition>* pa = new ComboOption<AFLPosition> (
2539                 "afl-position",
2540                 _("AFL signals come from"),
2541                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_afl_position),
2542                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_afl_position)
2543                 );
2544
2545         pa->add (AFLFromBeforeProcessors, _("immediately post-fader"));
2546         pa->add (AFLFromAfterProcessors, _("after post-fader processors (before pan)"));
2547
2548         add_option (_("Mixer"), pa);
2549
2550         add_option (_("Mixer"), new OptionEditorHeading (_("Default Track / Bus Muting Options")));
2551
2552         add_option (_("Mixer"),
2553              new BoolOption (
2554                      "mute-affects-pre-fader",
2555                      _("Mute affects pre-fader sends"),
2556                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_pre_fader),
2557                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_pre_fader)
2558                      ));
2559
2560         add_option (_("Mixer"),
2561              new BoolOption (
2562                      "mute-affects-post-fader",
2563                      _("Mute affects post-fader sends"),
2564                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_post_fader),
2565                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_post_fader)
2566                      ));
2567
2568         add_option (_("Mixer"),
2569              new BoolOption (
2570                      "mute-affects-control-outs",
2571                      _("Mute affects control outputs"),
2572                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_control_outs),
2573                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_control_outs)
2574                      ));
2575
2576         add_option (_("Mixer"),
2577              new BoolOption (
2578                      "mute-affects-main-outs",
2579                      _("Mute affects main outputs"),
2580                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_main_outs),
2581                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_main_outs)
2582                      ));
2583
2584
2585         if (!ARDOUR::Profile->get_mixbus()) {
2586                 add_option (_("Mixer"), new OptionEditorHeading (_("Send Routing")));
2587                 add_option (_("Mixer"),
2588                                 new BoolOption (
2589                                         "link-send-and-route-panner",
2590                                         _("Link panners of Aux and External Sends with main panner by default"),
2591                                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_link_send_and_route_panner),
2592                                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_link_send_and_route_panner)
2593                                         ));
2594         }
2595
2596         /* Signal Flow */
2597
2598         add_option (_("Signal Flow"), new OptionEditorHeading (_("Monitoring")));
2599
2600         ComboOption<MonitorModel>* mm = new ComboOption<MonitorModel> (
2601                 "monitoring-model",
2602                 _("Record monitoring handled by"),
2603                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_monitoring_model),
2604                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_monitoring_model)
2605                 );
2606
2607         if (AudioEngine::instance()->port_engine().can_monitor_input()) {
2608                 mm->add (HardwareMonitoring, _("via Audio Driver"));
2609         }
2610
2611         string prog (PROGRAM_NAME);
2612         boost::algorithm::to_lower (prog);
2613         mm->add (SoftwareMonitoring, string_compose (_("%1"), prog));
2614         mm->add (ExternalMonitoring, _("audio hardware"));
2615
2616         add_option (_("Signal Flow"), mm);
2617
2618         bo = new BoolOption (
2619                      "tape-machine-mode",
2620                      _("Tape machine mode"),
2621                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_tape_machine_mode),
2622                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_tape_machine_mode)
2623                      );
2624         add_option (_("Signal Flow"), bo);
2625         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2626                         string_compose (_("<b>When enabled</b> %1 will not monitor a track's input if the transport is stopped."),
2627                                         PROGRAM_NAME));
2628
2629         if (!Profile->get_mixbus()) {
2630
2631                 add_option (_("Signal Flow"), new OptionEditorHeading (_("Track and Bus Connections")));
2632
2633                 add_option (_("Signal Flow"),
2634                                 new BoolOption (
2635                                         "auto-connect-standard-busses",
2636                                         _("Auto-connect master/monitor busses"),
2637                                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_connect_standard_busses),
2638                                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_connect_standard_busses)
2639                                         ));
2640
2641                 ComboOption<AutoConnectOption>* iac = new ComboOption<AutoConnectOption> (
2642                                 "input-auto-connect",
2643                                 _("Connect track inputs"),
2644                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_input_auto_connect),
2645                                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_input_auto_connect)
2646                                 );
2647
2648                 iac->add (AutoConnectPhysical, _("automatically to physical inputs"));
2649                 iac->add (ManualConnect, _("manually"));
2650
2651                 add_option (_("Signal Flow"), iac);
2652
2653                 ComboOption<AutoConnectOption>* oac = new ComboOption<AutoConnectOption> (
2654                                 "output-auto-connect",
2655                                 _("Connect track and bus outputs"),
2656                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_output_auto_connect),
2657                                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_output_auto_connect)
2658                                 );
2659
2660                 oac->add (AutoConnectPhysical, _("automatically to physical outputs"));
2661                 oac->add (AutoConnectMaster, _("automatically to master bus"));
2662                 oac->add (ManualConnect, _("manually"));
2663
2664                 add_option (_("Signal Flow"), oac);
2665
2666                 bo = new BoolOption (
2667                                 "strict-io",
2668                                 _("Use 'Strict-I/O' for new tracks or busses"),
2669                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_strict_io),
2670                                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_strict_io)
2671                                 );
2672
2673                 add_option (_("Signal Flow"), bo);
2674                 Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2675                                 _("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."));
2676
2677         }  // !mixbus
2678
2679
2680         /* AUDIO */
2681
2682         add_option (_("Audio"), new OptionEditorHeading (_("Buffering")));
2683
2684         add_option (_("Audio"), new BufferingOptions (_rc_config));
2685
2686         add_option (_("Audio"), new OptionEditorHeading (_("Denormals")));
2687
2688         add_option (_("Audio"),
2689              new BoolOption (
2690                      "denormal-protection",
2691                      _("Use DC bias to protect against denormals"),
2692                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_protection),
2693                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_protection)
2694                      ));
2695
2696         ComboOption<DenormalModel>* dm = new ComboOption<DenormalModel> (
2697                 "denormal-model",
2698                 _("Processor handling"),
2699                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_model),
2700                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_model)
2701                 );
2702
2703         int dmsize = 1;
2704         dm->add (DenormalNone, _("no processor handling"));
2705
2706         FPU* fpu = FPU::instance();
2707
2708         if (fpu->has_flush_to_zero()) {
2709                 ++dmsize;
2710                 dm->add (DenormalFTZ, _("use FlushToZero"));
2711         } else if (_rc_config->get_denormal_model() == DenormalFTZ) {
2712                 _rc_config->set_denormal_model(DenormalNone);
2713         }
2714
2715         if (fpu->has_denormals_are_zero()) {
2716                 ++dmsize;
2717                 dm->add (DenormalDAZ, _("use DenormalsAreZero"));
2718         } else if (_rc_config->get_denormal_model() == DenormalDAZ) {
2719                 _rc_config->set_denormal_model(DenormalNone);
2720         }
2721
2722         if (fpu->has_flush_to_zero() && fpu->has_denormals_are_zero()) {
2723                 ++dmsize;
2724                 dm->add (DenormalFTZDAZ, _("use FlushToZero and DenormalsAreZero"));
2725         } else if (_rc_config->get_denormal_model() == DenormalFTZDAZ) {
2726                 _rc_config->set_denormal_model(DenormalNone);
2727         }
2728
2729         if (dmsize == 1) {
2730                 dm->set_sensitive(false);
2731         }
2732
2733         add_option (_("Audio"), dm);
2734
2735         add_option (_("Audio"), new OptionEditorHeading (_("Regions")));
2736
2737         add_option (_("Audio"),
2738              new BoolOption (
2739                      "auto-analyse-audio",
2740                      _("Enable automatic analysis of audio"),
2741                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_analyse_audio),
2742                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_analyse_audio)
2743                      ));
2744
2745         add_option (_("Audio"),
2746              new BoolOption (
2747                      "replicate-missing-region-channels",
2748                      _("Replicate missing region channels"),
2749                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_replicate_missing_region_channels),
2750                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_replicate_missing_region_channels)
2751                      ));
2752
2753         /* MIDI */
2754
2755         add_option (_("MIDI"), new OptionEditorHeading (_("Buffering")));
2756
2757         add_option (_("MIDI"),
2758                     new SpinOption<float> (
2759                             "midi-readahead",
2760                             _("MIDI read-ahead time (seconds)"),
2761                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_readahead),
2762                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_readahead),
2763                             0.1, 10, 0.05, 1,
2764                             "", 1.0, 2
2765                             ));
2766
2767         add_option (_("MIDI"), new OptionEditorHeading (_("Session")));
2768
2769         add_option (_("MIDI"),
2770              new SpinOption<int32_t> (
2771                      "initial-program-change",
2772                      _("Initial program change"),
2773                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_initial_program_change),
2774                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_initial_program_change),
2775                      -1, 65536, 1, 10
2776                      ));
2777
2778         add_option (_("MIDI"), new OptionEditorHeading (_("Audition")));
2779
2780         add_option (_("MIDI"),
2781              new BoolOption (
2782                      "sound-midi-notes",
2783                      _("Sound MIDI notes as they are selected in the editor"),
2784                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_sound_midi_notes),
2785                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_sound_midi_notes)
2786                      ));
2787
2788         ComboOption<std::string>* audition_synth = new ComboOption<std::string> (
2789                 "midi-audition-synth-uri",
2790                 _("MIDI Audition Synth (LV2)"),
2791                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_audition_synth_uri),
2792                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_audition_synth_uri)
2793                 );
2794
2795         audition_synth->add(X_(""), _("None"));
2796         PluginInfoList all_plugs;
2797         PluginManager& manager (PluginManager::instance());
2798 #ifdef LV2_SUPPORT
2799         all_plugs.insert (all_plugs.end(), manager.lv2_plugin_info().begin(), manager.lv2_plugin_info().end());
2800
2801         for (PluginInfoList::const_iterator i = all_plugs.begin(); i != all_plugs.end(); ++i) {
2802                 if (manager.get_status (*i) == PluginManager::Hidden) continue;
2803                 if (!(*i)->is_instrument()) continue;
2804                 if ((*i)->type != ARDOUR::LV2) continue;
2805                 if ((*i)->name.length() > 46) {
2806                         audition_synth->add((*i)->unique_id, (*i)->name.substr (0, 44) + "...");
2807                 } else {
2808                         audition_synth->add((*i)->unique_id, (*i)->name);
2809                 }
2810         }
2811 #endif
2812
2813         add_option (_("MIDI"), audition_synth);
2814
2815         /* Click */
2816
2817         add_option (_("Metronome"), new OptionEditorHeading (_("Metronome")));
2818         add_option (_("Metronome"), new ClickOptions (_rc_config));
2819         add_option (_("Metronome"), new OptionEditorHeading (_("Options")));
2820
2821         bo = new BoolOption (
2822                         "click-record-only",
2823                         _("Enable metronome only while recording"),
2824                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_click_record_only),
2825                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_click_record_only)
2826                         );
2827
2828         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2829                         string_compose (_("<b>When enabled</b> the metronome will remain silent if %1 is <b>not recording</b>."), PROGRAM_NAME));
2830         add_option (_("Metronome"), bo);
2831         add_option (_("Metronome"), new OptionEditorBlank ());
2832
2833
2834         /* Meters */
2835
2836         add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Metering")));
2837
2838         ComboOption<float>* mht = new ComboOption<float> (
2839                 "meter-hold",
2840                 _("Peak hold time"),
2841                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_hold),
2842                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_hold)
2843                 );
2844
2845         mht->add (MeterHoldOff, _("off"));
2846         mht->add (MeterHoldShort, _("short"));
2847         mht->add (MeterHoldMedium, _("medium"));
2848         mht->add (MeterHoldLong, _("long"));
2849
2850         add_option (S_("Preferences|Metering"), mht);
2851
2852         ComboOption<float>* mfo = new ComboOption<float> (
2853                 "meter-falloff",
2854                 _("DPM fall-off"),
2855                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_falloff),
2856                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_falloff)
2857                 );
2858
2859         mfo->add (METER_FALLOFF_OFF,      _("off"));
2860         mfo->add (METER_FALLOFF_SLOWEST,  _("slowest [6.6dB/sec]"));
2861         mfo->add (METER_FALLOFF_SLOW,     _("slow [8.6dB/sec] (BBC PPM, EBU PPM)"));
2862         mfo->add (METER_FALLOFF_SLOWISH,  _("moderate [12.0dB/sec] (DIN)"));
2863         mfo->add (METER_FALLOFF_MODERATE, _("medium [13.3dB/sec] (EBU Digi PPM, IRT Digi PPM)"));
2864         mfo->add (METER_FALLOFF_MEDIUM,   _("fast [20dB/sec]"));
2865         mfo->add (METER_FALLOFF_FAST,     _("very fast [32dB/sec]"));
2866
2867         add_option (S_("Preferences|Metering"), mfo);
2868
2869         ComboOption<MeterLineUp>* mlu = new ComboOption<MeterLineUp> (
2870                 "meter-line-up-level",
2871                 _("Meter line-up level; 0dBu"),
2872                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_line_up_level),
2873                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_line_up_level)
2874                 );
2875
2876         mlu->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
2877         mlu->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
2878         mlu->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
2879         mlu->add (MeteringLineUp15, _("-15dBFS (DIN)"));
2880
2881         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."));
2882
2883         add_option (S_("Preferences|Metering"), mlu);
2884
2885         ComboOption<MeterLineUp>* mld = new ComboOption<MeterLineUp> (
2886                 "meter-line-up-din",
2887                 _("IEC1/DIN Meter line-up level; 0dBu"),
2888                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_line_up_din),
2889                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_line_up_din)
2890                 );
2891
2892         mld->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
2893         mld->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
2894         mld->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
2895         mld->add (MeteringLineUp15, _("-15dBFS (DIN)"));
2896
2897         Gtkmm2ext::UI::instance()->set_tip (mld->tip_widget(), _("Reference level for IEC1/DIN meter."));
2898
2899         add_option (S_("Preferences|Metering"), mld);
2900
2901         ComboOption<VUMeterStandard>* mvu = new ComboOption<VUMeterStandard> (
2902                 "meter-vu-standard",
2903                 _("VU Meter standard"),
2904                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_vu_standard),
2905                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_vu_standard)
2906                 );
2907
2908         mvu->add (MeteringVUfrench,   _("0VU = -2dBu (France)"));
2909         mvu->add (MeteringVUamerican, _("0VU = 0dBu (North America, Australia)"));
2910         mvu->add (MeteringVUstandard, _("0VU = +4dBu (standard)"));
2911         mvu->add (MeteringVUeight,    _("0VU = +8dBu"));
2912
2913         add_option (S_("Preferences|Metering"), mvu);
2914
2915         HSliderOption *mpks = new HSliderOption("meter-peak",
2916                         _("Peak indicator threshold [dBFS]"),
2917                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_peak),
2918                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_peak),
2919                         -10, 0, .1, .1
2920                         );
2921
2922         Gtkmm2ext::UI::instance()->set_tip (
2923                         mpks->tip_widget(),
2924                         _("Specify the audio signal level in dBFS at and above which the meter-peak indicator will flash red."));
2925
2926         add_option (S_("Preferences|Metering"), mpks);
2927
2928         OptionEditorHeading* default_meter_head = new OptionEditorHeading (_("Default Meter Types"));
2929         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."));
2930
2931         add_option (S_("Preferences|Metering"), default_meter_head);
2932
2933         ComboOption<MeterType>* mtm = new ComboOption<MeterType> (
2934                 "meter-type-master",
2935                 _("Default Meter Type for Master Bus"),
2936                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_master),
2937                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_master)
2938                 );
2939         mtm->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
2940         mtm->add (MeterK20,     ArdourMeter::meter_type_string(MeterK20));
2941         mtm->add (MeterK14,     ArdourMeter::meter_type_string(MeterK14));
2942         mtm->add (MeterK12,     ArdourMeter::meter_type_string(MeterK12));
2943         mtm->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
2944         mtm->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
2945         mtm->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
2946         mtm->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
2947
2948         add_option (S_("Preferences|Metering"), mtm);
2949
2950
2951         ComboOption<MeterType>* mtb = new ComboOption<MeterType> (
2952                 "meter-type-bus",
2953                 _("Default meter type for busses"),
2954                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_bus),
2955                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_bus)
2956                 );
2957         mtb->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
2958         mtb->add (MeterK20,     ArdourMeter::meter_type_string(MeterK20));
2959         mtb->add (MeterK14,     ArdourMeter::meter_type_string(MeterK14));
2960         mtb->add (MeterK12,     ArdourMeter::meter_type_string(MeterK12));
2961         mtb->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
2962         mtb->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
2963         mtb->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
2964         mtb->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
2965
2966         add_option (S_("Preferences|Metering"), mtb);
2967
2968         ComboOption<MeterType>* mtt = new ComboOption<MeterType> (
2969                 "meter-type-track",
2970                 _("Default meter type for tracks"),
2971                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_track),
2972                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_track)
2973                 );
2974         mtt->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
2975         mtt->add (MeterPeak0dB, ArdourMeter::meter_type_string(MeterPeak0dB));
2976
2977         add_option (S_("Preferences|Metering"), mtt);
2978
2979         add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Post Export Analysis")));
2980
2981         add_option (S_("Preferences|Metering"),
2982              new BoolOption (
2983                      "save-export-analysis-image",
2984                      _("Save loudness analysis as image file"),
2985                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_save_export_analysis_image),
2986                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_save_export_analysis_image)
2987                      ));
2988
2989         /* TRANSPORT & Sync */
2990
2991         add_option (_("Transport"), new OptionEditorHeading (_("General")));
2992
2993         bo = new BoolOption (
2994                      "stop-at-session-end",
2995                      _("Stop at the end of the session"),
2996                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_at_session_end),
2997                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_at_session_end)
2998                      );
2999         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3000                                             string_compose (_("<b>When enabled</b> if %1 is <b>not recording</b>, it will stop the transport "
3001                                                               "when it reaches the current session end marker\n\n"
3002                                                               "<b>When disabled</b> %1 will continue to roll past the session end marker at all times"),
3003                                                             PROGRAM_NAME));
3004         add_option (_("Transport"), bo);
3005
3006         bo = new BoolOption (
3007                      "latched-record-enable",
3008                      _("Keep record-enable engaged on stop"),
3009                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_latched_record_enable),
3010                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_latched_record_enable)
3011                      );
3012         add_option (_("Transport"), bo);
3013         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3014                         _("<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."));
3015
3016         bo = new BoolOption (
3017                      "disable-disarm-during-roll",
3018                      _("Disable per-track record disarm while rolling"),
3019                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_disable_disarm_during_roll),
3020                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_disable_disarm_during_roll)
3021                      );
3022         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."));
3023         add_option (_("Transport"), bo);
3024
3025         bo = new BoolOption (
3026                      "quieten_at_speed",
3027                      _("12dB gain reduction during fast-forward and fast-rewind"),
3028                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_quieten_at_speed),
3029                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_quieten_at_speed)
3030                      );
3031         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3032                         _("<b>When enabled</b> this will reduce the unpleasant increase in perceived volume "
3033                                 "that occurs when fast-forwarding or rewinding through some kinds of audio"));
3034         add_option (_("Transport"), bo);
3035
3036         ComboOption<float>* psc = new ComboOption<float> (
3037                      "preroll-seconds",
3038                      _("Preroll"),
3039                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_preroll_seconds),
3040                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_preroll_seconds)
3041                      );
3042         Gtkmm2ext::UI::instance()->set_tip (psc->tip_widget(),
3043                                             (_("The amount of preroll to apply when <b>Play with Preroll</b> or <b>Record with Preroll</b>is initiated.\n\n"
3044                                                "If <b>Follow Edits</b> is enabled, the preroll is applied to the playhead position when a region is selected or trimmed.")));
3045         psc->add (-4.0, _("4 Bars"));
3046         psc->add (-2.0, _("2 Bars"));
3047         psc->add (-1.0, _("1 Bar"));
3048         psc->add (0.0, _("0 (no pre-roll)"));
3049         psc->add (0.1, _("0.1 second"));
3050         psc->add (0.25, _("0.25 second"));
3051         psc->add (0.5, _("0.5 second"));
3052         psc->add (1.0, _("1.0 second"));
3053         psc->add (2.0, _("2.0 seconds"));
3054         add_option (_("Transport"), psc);
3055
3056
3057         add_option (_("Transport"), new OptionEditorHeading (_("Looping")));
3058
3059         bo = new BoolOption (
3060                      "loop-is-mode",
3061                      _("Play loop is a transport mode"),
3062                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_loop_is_mode),
3063                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_loop_is_mode)
3064                      );
3065         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3066                                             (_("<b>When enabled</b> the loop button does not start playback but forces playback to always play the loop\n\n"
3067                                                "<b>When disabled</b> the loop button starts playing the loop, but stop then cancels loop playback")));
3068         add_option (_("Transport"), bo);
3069
3070         bo = new BoolOption (
3071                      "seamless-loop",
3072                      _("Do seamless looping (not possible when slaved to MTC, LTC etc)"),
3073                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_seamless_loop),
3074                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_seamless_loop)
3075                      );
3076         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3077                                             string_compose (_("<b>When enabled</b> this will loop by reading ahead and wrapping around at the loop point, "
3078                                                               "preventing any need to do a transport locate at the end of the loop\n\n"
3079                                                               "<b>When disabled</b> looping is done by locating back to the start of the loop when %1 reaches the end "
3080                                                               "which will often cause a small click or delay"), PROGRAM_NAME));
3081         add_option (_("Transport"), bo);
3082
3083         add_option (_("Transport"), new OptionEditorHeading (_("Dropout (xrun) Handling")));
3084         bo = new BoolOption (
3085                      "stop-recording-on-xrun",
3086                      _("Stop recording when an xrun occurs"),
3087                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_recording_on_xrun),
3088                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_recording_on_xrun)
3089                      );
3090         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3091                                             string_compose (_("<b>When enabled</b> %1 will stop recording if an over- or underrun is detected by the audio engine"),
3092                                                             PROGRAM_NAME));
3093         add_option (_("Transport"), bo);
3094
3095         bo = new BoolOption (
3096                      "create-xrun-marker",
3097                      _("Create markers where xruns occur"),
3098                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_create_xrun_marker),
3099                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_create_xrun_marker)
3100                      );
3101         add_option (_("Transport"), bo);
3102
3103
3104         /* SYNC */
3105
3106         add_option (_("Sync"), new OptionEditorHeading (_("External Synchronization")));
3107
3108         _sync_source = new ComboOption<SyncSource> (
3109                 "sync-source",
3110                 _("External timecode source"),
3111                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_sync_source),
3112                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_sync_source)
3113                 );
3114
3115         add_option (_("Sync"), _sync_source);
3116
3117         _sync_framerate = new BoolOption (
3118                      "timecode-sync-frame-rate",
3119                      _("Match session video frame rate to external timecode"),
3120                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_sync_frame_rate),
3121                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_sync_frame_rate)
3122                      );
3123         Gtkmm2ext::UI::instance()->set_tip
3124                 (_sync_framerate->tip_widget(),
3125                  string_compose (_("This option controls the value of the video frame rate <i>while chasing</i> an external timecode source.\n\n"
3126                                    "<b>When enabled</b> the session video frame rate will be changed to match that of the selected external timecode source.\n\n"
3127                                    "<b>When disabled</b> the session video frame rate will not be changed to match that of the selected external timecode source."
3128                                    "Instead the frame rate indication in the main clock will flash red and %1 will convert between the external "
3129                                    "timecode standard and the session standard."), PROGRAM_NAME));
3130
3131         add_option (_("Sync"), _sync_framerate);
3132
3133         _sync_genlock = new BoolOption (
3134                 "timecode-source-is-synced",
3135                 _("Sync-lock timecode to clock (disable drift compensation)"),
3136                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_is_synced),
3137                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_is_synced)
3138                 );
3139         Gtkmm2ext::UI::instance()->set_tip
3140                 (_sync_genlock->tip_widget(),
3141                  string_compose (_("<b>When enabled</b> %1 will never varispeed when slaved to external timecode. "
3142                                    "Sync Lock indicates that the selected external timecode source shares clock-sync "
3143                                    "(Black &amp; Burst, Wordclock, etc) with the audio interface. "
3144                                    "This option disables drift compensation. The transport speed is fixed at 1.0. "
3145                                    "Vari-speed LTC will be ignored and cause drift."
3146                                    "\n\n"
3147                                    "<b>When disabled</b> %1 will compensate for potential drift, regardless if the "
3148                                    "timecode sources shares clock sync."
3149                                   ), PROGRAM_NAME));
3150
3151
3152         add_option (_("Sync"), _sync_genlock);
3153
3154         _sync_source_2997 = new BoolOption (
3155                 "timecode-source-2997",
3156                 _("Lock to 29.9700 fps instead of 30000/1001"),
3157                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_2997),
3158                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_2997)
3159                 );
3160         Gtkmm2ext::UI::instance()->set_tip
3161                 (_sync_source_2997->tip_widget(),
3162                  _("<b>When enabled</b> the external timecode source is assumed to use 29.97 fps instead of 30000/1001.\n"
3163                          "SMPTE 12M-1999 specifies 29.97df as 30000/1001. The spec further mentions that "
3164                          "drop-frame timecode has an accumulated error of -86ms over a 24-hour period.\n"
3165                          "Drop-frame timecode would compensate exactly for a NTSC color frame rate of 30 * 0.9990 (ie 29.970000). "
3166                          "That is not the actual rate. However, some vendors use that rate - despite it being against the specs - "
3167                          "because the variant of using exactly 29.97 fps has zero timecode drift.\n"
3168                          ));
3169
3170         add_option (_("Sync"), _sync_source_2997);
3171
3172         add_option (_("Sync/LTC"), new OptionEditorHeading (_("Linear Timecode (LTC) Reader")));
3173
3174         _ltc_port = new ComboStringOption (
3175                 "ltc-source-port",
3176                 _("LTC incoming port"),
3177                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_source_port),
3178                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_source_port)
3179                 );
3180
3181         vector<string> physical_inputs;
3182         physical_inputs.push_back (_("None"));
3183         AudioEngine::instance()->get_physical_inputs (DataType::AUDIO, physical_inputs);
3184         _ltc_port->set_popdown_strings (physical_inputs);
3185
3186         populate_sync_options ();
3187         AudioEngine::instance()->Running.connect (engine_started_connection, MISSING_INVALIDATOR, boost::bind (&RCOptionEditor::populate_sync_options, this), gui_context());
3188
3189         add_option (_("Sync/LTC"), _ltc_port);
3190
3191         add_option (_("Sync/LTC"), new OptionEditorHeading (_("Linear Timecode (LTC) Generator")));
3192
3193         add_option (_("Sync/LTC"),
3194                     new BoolOption (
3195                             "send-ltc",
3196                             _("Enable LTC generator"),
3197                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_ltc),
3198                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_ltc)
3199                             ));
3200
3201         _ltc_send_continuously = new BoolOption (
3202                             "ltc-send-continuously",
3203                             _("Send LTC while stopped"),
3204                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_send_continuously),
3205                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_send_continuously)
3206                             );
3207         Gtkmm2ext::UI::instance()->set_tip
3208                 (_ltc_send_continuously->tip_widget(),
3209                  string_compose (_("<b>When enabled</b> %1 will continue to send LTC information even when the transport (playhead) is not moving"), PROGRAM_NAME));
3210         add_option (_("Sync/LTC"), _ltc_send_continuously);
3211
3212         _ltc_volume_slider = new HSliderOption("ltcvol", _("LTC generator level [dBFS]"),
3213                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_output_volume),
3214                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_output_volume),
3215                                         -50, 0, .5, 5,
3216                                         .05, true);
3217
3218         Gtkmm2ext::UI::instance()->set_tip
3219                 (_ltc_volume_slider->tip_widget(),
3220                  _("Specify the Peak Volume of the generated LTC signal in dBFS. A good value is  0dBu ^= -18dBFS in an EBU calibrated system"));
3221
3222         add_option (_("Sync/LTC"), _ltc_volume_slider);
3223
3224
3225         add_option (_("Sync/MIDI"), new OptionEditorHeading (_("MIDI Beat Clock (Mclk) Generator")));
3226
3227         add_option (_("Sync/MIDI"),
3228                     new BoolOption (
3229                             "send-midi-clock",
3230                             _("Enable Mclk generator"),
3231                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_midi_clock),
3232                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_midi_clock)
3233                             ));
3234
3235         add_option (_("Sync/MIDI"), new OptionEditorHeading (_("MIDI Time Code (MTC) Generator")));
3236
3237         add_option (_("Sync/MIDI"),
3238                     new BoolOption (
3239                             "send-mtc",
3240                             _("Enable MTC Generator"),
3241                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mtc),
3242                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mtc)
3243                             ));
3244
3245         add_option (_("Sync/MIDI"),
3246                     new SpinOption<int> (
3247                             "mtc-qf-speed-tolerance",
3248                             _("Percentage either side of normal transport speed to transmit MTC"),
3249                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mtc_qf_speed_tolerance),
3250                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mtc_qf_speed_tolerance),
3251                             0, 20, 1, 5
3252                             ));
3253
3254         add_option (_("Sync/MIDI"), new OptionEditorHeading (_("MIDI Machine Control (MMC)")));
3255
3256         add_option (_("Sync/MIDI"),
3257                     new BoolOption (
3258                             "mmc-control",
3259                             _("Respond to MMC commands"),
3260                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_control),
3261                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_control)
3262                             ));
3263
3264         add_option (_("Sync/MIDI"),
3265                     new BoolOption (
3266                             "send-mmc",
3267                             _("Send MMC commands"),
3268                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mmc),
3269                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mmc)
3270                             ));
3271
3272         add_option (_("Sync/MIDI"),
3273              new SpinOption<uint8_t> (
3274                      "mmc-receive-device-id",
3275                      _("Inbound MMC device ID"),
3276                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_receive_device_id),
3277                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_receive_device_id),
3278                      0, 128, 1, 10
3279                      ));
3280
3281         add_option (_("Sync/MIDI"),
3282              new SpinOption<uint8_t> (
3283                      "mmc-send-device-id",
3284                      _("Outbound MMC device ID"),
3285                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_send_device_id),
3286                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_send_device_id),
3287                      0, 128, 1, 10
3288                      ));
3289
3290
3291         /* Control Surfaces */
3292
3293         add_option (_("Control Surfaces"), new OptionEditorHeading (_("Control Surfaces")));
3294         add_option (_("Control Surfaces"), new ControlSurfacesOptions ());
3295
3296         /* MIDI PORTs */
3297         add_option (_("MIDI Ports"), new OptionEditorHeading (_("MIDI Port Options")));
3298
3299         add_option (_("MIDI Ports"),
3300                     new BoolOption (
3301                             "get-midi-input-follows-selection",
3302                             _("MIDI input follows MIDI track selection"),
3303                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_input_follows_selection),
3304                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_input_follows_selection)
3305                             ));
3306
3307         add_option (_("MIDI Ports"), new MidiPortOptions ());
3308         add_option (_("MIDI Ports"), new OptionEditorBlank ());
3309
3310         /* PLUGINS */
3311
3312 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT || defined AUDIOUNIT_SUPPORT)
3313         add_option (_("Plugins"), new OptionEditorHeading (_("Scan/Discover")));
3314         add_option (_("Plugins"),
3315                         new RcActionButton (_("Scan for Plugins"),
3316                                 sigc::mem_fun (*this, &RCOptionEditor::plugin_scan_refresh)));
3317
3318 #endif
3319
3320         add_option (_("Plugins"), new OptionEditorHeading (_("General")));
3321
3322 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT || defined AUDIOUNIT_SUPPORT)
3323         bo = new BoolOption (
3324                         "show-plugin-scan-window",
3325                         _("Always Display Plugin Scan Progress"),
3326                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_plugin_scan_window),
3327                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_plugin_scan_window)
3328                         );
3329         add_option (_("Plugins"), bo);
3330         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3331                         _("<b>When enabled</b> a popup window showing plugin scan progress is displayed for indexing (cache load) and discovery (detect new plugins)"));
3332 #endif
3333
3334         bo = new BoolOption (
3335                 "plugins-stop-with-transport",
3336                 _("Silence plugins when the transport is stopped"),
3337                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugins_stop_with_transport),
3338                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_plugins_stop_with_transport)
3339                 );
3340         add_option (_("Plugins"), bo);
3341         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3342                                             _("<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."));
3343
3344         bo = new BoolOption (
3345                 "new-plugins-active",
3346                         _("Make new plugins active"),
3347                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_new_plugins_active),
3348                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_new_plugins_active)
3349                         );
3350         add_option (_("Plugins"), bo);
3351         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3352                                             _("<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"));
3353
3354 #if (defined WINDOWS_VST_SUPPORT || defined MACVST_SUPPORT || defined LXVST_SUPPORT)
3355         add_option (_("Plugins/VST"), new OptionEditorHeading (_("VST")));
3356 #if 0
3357         add_option (_("Plugins/VST"),
3358                         new RcActionButton (_("Scan for Plugins"),
3359                                 sigc::mem_fun (*this, &RCOptionEditor::plugin_scan_refresh)));
3360 #endif
3361
3362 #if (defined AUDIOUNIT_SUPPORT && defined MACVST_SUPPORT)
3363         bo = new BoolOption (
3364                         "",
3365                         _("Enable Mac VST support (requires restart or re-scan)"),
3366                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_use_macvst),
3367                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_use_macvst)
3368                         );
3369         add_option (_("Plugins/VST"), bo);
3370 #endif
3371
3372         bo = new BoolOption (
3373                         "discover-vst-on-start",
3374                         _("Scan for [new] VST Plugins on Application Start"),
3375                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_discover_vst_on_start),
3376                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_discover_vst_on_start)
3377                         );
3378         add_option (_("Plugins/VST"), bo);
3379         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3380                                             _("<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"));
3381
3382 #ifdef WINDOWS_VST_SUPPORT
3383         // currently verbose logging is only implemented for Windows VST.
3384         bo = new BoolOption (
3385                         "verbose-plugin-scan",
3386                         _("Verbose Plugin Scan"),
3387                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_verbose_plugin_scan),
3388                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_verbose_plugin_scan)
3389                         );
3390         add_option (_("Plugins/VST"), bo);
3391         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3392                                             _("<b>When enabled</b> additional information for every plugin is added to the Log Window."));
3393 #endif
3394
3395         add_option (_("Plugins/VST"), new VstTimeOutSliderOption (_rc_config));
3396
3397         add_option (_("Plugins/VST"),
3398                         new RcActionButton (_("Clear"),
3399                                 sigc::mem_fun (*this, &RCOptionEditor::clear_vst_cache),
3400                                 _("VST Cache:")));
3401
3402         add_option (_("Plugins/VST"),
3403                         new RcActionButton (_("Clear"),
3404                                 sigc::mem_fun (*this, &RCOptionEditor::clear_vst_blacklist),
3405                                 _("VST Blacklist:")));
3406 #endif
3407
3408 #ifdef LXVST_SUPPORT
3409         add_option (_("Plugins/VST"),
3410                         new RcActionButton (_("Edit"),
3411                                 sigc::mem_fun (*this, &RCOptionEditor::edit_lxvst_path),
3412                         _("Linux VST Path:")));
3413
3414         add_option (_("Plugins/VST"),
3415                         new RcConfigDisplay (
3416                                 "plugin-path-lxvst",
3417                                 _("Path:"),
3418                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugin_path_lxvst),
3419                                 0));
3420 #endif
3421
3422 #ifdef WINDOWS_VST_SUPPORT
3423         add_option (_("Plugins/VST"),
3424                         new RcActionButton (_("Edit"),
3425                                 sigc::mem_fun (*this, &RCOptionEditor::edit_vst_path),
3426                         _("Windows VST Path:")));
3427         add_option (_("Plugins/VST"),
3428                         new RcConfigDisplay (
3429                                 "plugin-path-vst",
3430                                 _("Path:"),
3431                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugin_path_vst),
3432                                 ';'));
3433 #endif
3434
3435 #ifdef AUDIOUNIT_SUPPORT
3436
3437         add_option (_("Plugins/Audio Unit"), new OptionEditorHeading (_("Audio Unit")));
3438 #if 0
3439         add_option (_("Plugins/Audio Unit"),
3440                         new RcActionButton (_("Scan for Plugins"),
3441                                 sigc::mem_fun (*this, &RCOptionEditor::plugin_scan_refresh)));
3442 #endif
3443
3444         bo = new BoolOption (
3445                         "discover-audio-units",
3446                         _("Scan for [new] AudioUnit Plugins on Application Start"),
3447                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_discover_audio_units),
3448                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_discover_audio_units)
3449                         );
3450         add_option (_("Plugins/Audio Unit"), bo);
3451         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3452                                             _("<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."));
3453
3454         add_option (_("Plugins/Audio Unit"),
3455                         new RcActionButton (_("Clear"),
3456                                 sigc::mem_fun (*this, &RCOptionEditor::clear_au_cache),
3457                                 _("AU Cache:")));
3458
3459         add_option (_("Plugins/Audio Unit"),
3460                         new RcActionButton (_("Clear"),
3461                                 sigc::mem_fun (*this, &RCOptionEditor::clear_au_blacklist),
3462                                 _("AU Blacklist:")));
3463 #endif
3464
3465 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT || defined AUDIOUNIT_SUPPORT || defined HAVE_LV2)
3466         add_option (_("Plugins"), new OptionEditorHeading (_("Plugin GUI")));
3467         add_option (_("Plugins"),
3468              new BoolOption (
3469                      "open-gui-after-adding-plugin",
3470                      _("Automatically open the plugin GUI when adding a new plugin"),
3471                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_open_gui_after_adding_plugin),
3472                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_open_gui_after_adding_plugin)
3473                      ));
3474
3475 #if (defined LV2_SUPPORT && defined LV2_EXTENDED)
3476         add_option (_("Plugins"),
3477              new BoolOption (
3478                      "show-inline-display-by-default",
3479                      _("Show Plugin Inline Display on Mixerstrip by default"),
3480                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_inline_display_by_default),
3481                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_inline_display_by_default)
3482                      ));
3483
3484         _plugin_prefer_inline = new BoolOption (
3485                         "prefer-inline-over-gui",
3486                         _("Don't automatically open the plugin GUI when the plugin has an inline display mode"),
3487                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_prefer_inline_over_gui),
3488                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_prefer_inline_over_gui)
3489                         );
3490         add_option (_("Plugins"), _plugin_prefer_inline);
3491 #endif
3492
3493         add_option (_("Plugins"), new OptionEditorHeading (_("Instrument")));
3494
3495         bo = new BoolOption (
3496                         "ask-replace-instrument",
3497                         _("Ask to replace existing instrument plugin"),
3498                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_ask_replace_instrument),
3499                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_ask_replace_instrument)
3500                         );
3501         add_option (_("Plugins"), bo);
3502
3503         bo = new BoolOption (
3504                         "ask-setup_instrument",
3505                         _("Interactively configure instrument plugins on insert"),
3506                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_ask_setup_instrument),
3507                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_ask_setup_instrument)
3508                         );
3509         add_option (_("Plugins"), bo);
3510         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3511                         _("<b>When enabled</b> show a dialog to select instrument channel configuration before adding a multichannel plugin."));
3512
3513 #endif
3514         add_option (_("Plugins"), new OptionEditorBlank ());
3515
3516         /* INTERFACE */
3517 #if (defined OPTIONAL_CAIRO_IMAGE_SURFACE || defined CAIRO_SUPPORTS_FORCE_BUGGY_GRADIENTS_ENVIRONMENT_VARIABLE)
3518         add_option (_("Appearance"), new OptionEditorHeading (_("Graphics Acceleration")));
3519 #endif
3520
3521 #ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
3522         BoolOption* bgc = new BoolOption (
3523                 "cairo-image-surface",
3524                 _("Disable Graphics Hardware Acceleration (requires restart)"),
3525                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_cairo_image_surface),
3526                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_cairo_image_surface)
3527                 );
3528
3529         Gtkmm2ext::UI::instance()->set_tip (bgc->tip_widget(), string_compose (
3530                                 _("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));
3531         add_option (_("Appearance"), bgc);
3532 #endif
3533
3534 #ifdef CAIRO_SUPPORTS_FORCE_BUGGY_GRADIENTS_ENVIRONMENT_VARIABLE
3535         BoolOption* bgo = new BoolOption (
3536                 "buggy-gradients",
3537                 _("Possibly improve slow graphical performance (requires restart)"),
3538                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_buggy_gradients),
3539                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_buggy_gradients)
3540                 );
3541
3542         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));
3543         add_option (_("Appearance"), bgo);
3544 #endif
3545         add_option (_("Appearance"), new OptionEditorHeading (_("Graphical User Interface")));
3546
3547         add_option (_("Appearance"),
3548              new BoolOption (
3549                      "widget-prelight",
3550                      _("Highlight widgets on mouseover"),
3551                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_widget_prelight),
3552                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_widget_prelight)
3553                      ));
3554
3555         add_option (_("Appearance"),
3556              new BoolOption (
3557                      "use-tooltips",
3558                      _("Show tooltips if mouse hovers over a control"),
3559                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_tooltips),
3560                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_tooltips)
3561                      ));
3562
3563         bo = new BoolOption (
3564                         "super-rapid-clock-update",
3565                         _("Update clocks at TC Frame rate"),
3566                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_super_rapid_clock_update),
3567                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_super_rapid_clock_update)
3568                         );
3569         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3570                         _("<b>When enabled</b> clock displays are updated every Timecode Frame (fps).\n\n"
3571                                 "<b>When disabled</b> clock displays are updated only every 100ms."
3572                          ));
3573         add_option (_("Appearance"), bo);
3574
3575         add_option (_("Appearance"),
3576                         new BoolOption (
3577                                 "blink-rec-arm",
3578                                 _("Blink Rec-Arm buttons"),
3579                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_blink_rec_arm),
3580                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_blink_rec_arm)
3581                                 ));
3582
3583         add_option (_("Appearance"),
3584                         new BoolOption (
3585                                 "blink-alert-indicators",
3586                                 _("Blink Alert Indicators"),
3587                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_blink_alert_indicators),
3588                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_blink_alert_indicators)
3589                                 ));
3590
3591
3592 #ifndef __APPLE__
3593         /* font scaling does nothing with GDK/Quartz */
3594         add_option (_("Appearance"), new FontScalingOptions ());
3595 #endif
3596         add_option (_("Appearance/Editor"), new OptionEditorHeading (_("General")));
3597         add_option (_("Appearance/Editor"),
3598              new BoolOption (
3599                      "show-name-highlight",
3600                      _("Use name highlight bars in region displays (requires a restart)"),
3601                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_name_highlight),
3602                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_name_highlight)
3603                      ));
3604
3605         add_option (_("Appearance/Editor"),
3606                         new BoolOption (
3607                         "color-regions-using-track-color",
3608                         _("Region color follows track color"),
3609                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_color_regions_using_track_color),
3610                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_color_regions_using_track_color)
3611                         ));
3612
3613         add_option (_("Appearance/Editor"), new OptionEditorHeading (_("Waveforms")));
3614
3615         if (!Profile->get_mixbus()) {
3616                 add_option (_("Appearance/Editor"),
3617                                 new BoolOption (
3618                                         "show-waveforms",
3619                                         _("Show waveforms in regions"),
3620                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveforms),
3621                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveforms)
3622                                         ));
3623         }  // !mixbus
3624
3625         add_option (_("Appearance/Editor"),
3626              new BoolOption (
3627                      "show-waveforms-while-recording",
3628                      _("Show waveforms while recording"),
3629                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveforms_while_recording),
3630                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveforms_while_recording)
3631                      ));
3632
3633         add_option (_("Appearance/Editor"),
3634                         new BoolOption (
3635                         "show-waveform-clipping",
3636                         _("Show waveform clipping"),
3637                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveform_clipping),
3638                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveform_clipping)
3639                         ));
3640
3641         add_option (_("Appearance/Editor"), new ClipLevelOptions ());
3642
3643         ComboOption<WaveformScale>* wfs = new ComboOption<WaveformScale> (
3644                 "waveform-scale",
3645                 _("Waveform scale"),
3646                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_scale),
3647                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_scale)
3648                 );
3649
3650         wfs->add (Linear, _("linear"));
3651         wfs->add (Logarithmic, _("logarithmic"));
3652
3653         add_option (_("Appearance/Editor"), wfs);
3654
3655         ComboOption<WaveformShape>* wfsh = new ComboOption<WaveformShape> (
3656                 "waveform-shape",
3657                 _("Waveform shape"),
3658                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_shape),
3659                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_shape)
3660                 );
3661
3662         wfsh->add (Traditional, _("traditional"));
3663         wfsh->add (Rectified, _("rectified"));
3664
3665         add_option (_("Appearance/Editor"), wfsh);
3666
3667         add_option (_("Appearance/Editor"), new OptionEditorHeading (_("Editor Meters")));
3668
3669         add_option (_("Appearance/Editor"),
3670              new BoolOption (
3671                      "show-track-meters",
3672                      _("Show meters in track headers"),
3673                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_track_meters),
3674                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_track_meters)
3675                      ));
3676
3677         add_option (_("Appearance/Editor"),
3678              new BoolOption (
3679                      "editor-stereo-only-meters",
3680                      _("Limit track header meters to stereo"),
3681                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_editor_stereo_only_meters),
3682                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_editor_stereo_only_meters)
3683                      ));
3684
3685         add_option (_("Appearance/Editor"), new OptionEditorHeading (_("MIDI Regions")));
3686
3687         add_option (_("Appearance/Editor"),
3688                     new BoolOption (
3689                             "display-first-midi-bank-as-zero",
3690                             _("Display first MIDI bank/program as 0"),
3691                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_first_midi_bank_is_zero),
3692                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_first_midi_bank_is_zero)
3693                             ));
3694
3695         add_option (_("Appearance/Editor"),
3696              new BoolOption (
3697                      "never-display-periodic-midi",
3698                      _("Don't display periodic (MTC, MMC) SysEx messages in MIDI Regions"),
3699                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_never_display_periodic_midi),
3700                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_never_display_periodic_midi)
3701                      ));
3702
3703         add_option (_("Appearance/Editor"), new OptionEditorBlank ());
3704
3705         /* The names of these controls must be the same as those given in MixerStrip
3706            for the actual widgets being controlled.
3707         */
3708         _mixer_strip_visibility.add (0, X_("Input"), _("Input"));
3709         _mixer_strip_visibility.add (0, X_("PhaseInvert"), _("Phase Invert"));
3710         _mixer_strip_visibility.add (0, X_("RecMon"), _("Record & Monitor"));
3711         _mixer_strip_visibility.add (0, X_("SoloIsoLock"), _("Solo Iso / Lock"));
3712         _mixer_strip_visibility.add (0, X_("Output"), _("Output"));
3713         _mixer_strip_visibility.add (0, X_("Comments"), _("Comments"));
3714         _mixer_strip_visibility.add (0, X_("VCA"), _("VCA Assigns"));
3715
3716         add_option (_("Appearance/Mixer"),
3717                 new VisibilityOption (
3718                         _("Mixer Strip"),
3719                         &_mixer_strip_visibility,
3720                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_mixer_strip_visibility),
3721                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_mixer_strip_visibility)
3722                         )
3723                 );
3724
3725         add_option (_("Appearance/Mixer"),
3726              new BoolOption (
3727                      "default-narrow_ms",
3728                      _("Use narrow strips in the mixer for new strips by default"),
3729                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_default_narrow_ms),
3730                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_default_narrow_ms)
3731                      ));
3732
3733         add_option (_("Appearance/Mixer"), new OptionEditorBlank ());
3734
3735         add_option (_("Appearance/Toolbar"), new OptionEditorHeading (_("Main Transport Toolbar Items")));
3736
3737         add_option (_("Appearance/Toolbar"),
3738              new BoolOption (
3739                      "show-toolbar-recpunch",
3740                      _("Display Record/Punch Options"),
3741                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_toolbar_recpunch),
3742                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_toolbar_recpunch)
3743                      ));
3744
3745         add_option (_("Appearance/Toolbar"),
3746              new BoolOption (
3747                      "show-toolbar-monitoring",
3748                      _("Display Monitor Options"),
3749                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_toolbar_monitoring),
3750                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_toolbar_monitoring)
3751                      ));
3752
3753         add_option (_("Appearance/Toolbar"),
3754              new BoolOption (
3755                      "show-toolbar-selclock",
3756                      _("Display Selection Clock"),
3757                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_toolbar_selclock),
3758                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_toolbar_selclock)
3759                      ));
3760
3761         if (!ARDOUR::Profile->get_small_screen()) {
3762                 add_option (_("Appearance/Toolbar"),
3763                                 new BoolOption (
3764                                         "show-secondary-clock",
3765                                         _("Display Secondary Clock"),
3766                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_secondary_clock),
3767                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_secondary_clock)
3768                                         ));
3769         }
3770
3771         add_option (_("Appearance/Toolbar"),
3772              new BoolOption (
3773                      "show-mini-timeline",
3774                      _("Display Navigation Timeline"),
3775                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_mini_timeline),
3776                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_mini_timeline)
3777                      ));
3778
3779         add_option (_("Appearance/Toolbar"),
3780              new BoolOption (
3781                      "show-editor-meter",
3782                      _("Display Master Level Meter"),
3783                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_editor_meter),
3784                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_editor_meter)
3785                      ));
3786
3787         add_option (_("Appearance/Toolbar"),
3788                         new ColumVisibilityOption (
3789                                 "action-table-columns", _("Lua Action Script Button Visibility"), 4,
3790                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_action_table_columns),
3791                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_action_table_columns)
3792                                 )
3793                         );
3794         add_option (_("Appearance/Toolbar"), new OptionEditorBlank ());
3795
3796
3797         /* and now the theme manager */
3798
3799         add_option (_("Appearance/Theme"), new OptionEditorHeading (_("Theme")));
3800
3801         add_option (_("Appearance/Theme"), new BoolOption (
3802                                 "flat-buttons",
3803                                 _("Draw \"flat\" buttons"),
3804                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_flat_buttons),
3805                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_flat_buttons)
3806                                 ));
3807
3808         add_option (_("Appearance/Theme"), new BoolOption (
3809                                 "meter-style-led",
3810                                 _("LED meter style"),
3811                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_style_led),
3812                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_style_led)
3813                                 ));
3814
3815
3816         HSliderOption *gui_hs = new HSliderOption(
3817                         "timeline-item-gradient-depth",
3818                         _("Waveforms color gradient depth"),
3819                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_gradient_depth),
3820                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_gradient_depth),
3821                         0, 1.0, 0.05
3822                         );
3823         gui_hs->scale().set_update_policy (Gtk::UPDATE_DELAYED);
3824         add_option (_("Appearance/Theme"), gui_hs);
3825
3826         gui_hs = new HSliderOption(
3827                         "timeline-item-gradient-depth",
3828                         _("Timeline item gradient depth"),
3829                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_timeline_item_gradient_depth),
3830                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_timeline_item_gradient_depth),
3831                         0, 1.0, 0.05
3832                         );
3833         gui_hs->scale().set_update_policy (Gtk::UPDATE_DELAYED);
3834         add_option (_("Appearance/Theme"), gui_hs);
3835
3836         vector<string> icon_sets = ::get_icon_sets ();
3837         if (icon_sets.size() > 1) {
3838                 ComboOption<std::string>* io = new ComboOption<std::string> (
3839                                 "icon-set", _("Icon Set"),
3840                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_icon_set),
3841                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_icon_set)
3842                                 );
3843                 for (vector<string>::const_iterator i = icon_sets.begin (); i != icon_sets.end (); ++i) {
3844                         io->add (*i, *i);
3845                 }
3846                 add_option (_("Appearance/Theme"), io);
3847         }
3848
3849         add_option (_("Appearance/Colors"), new OptionEditorHeading (_("Colors")));
3850         add_option (_("Appearance/Colors"), new ColorThemeManager);
3851         add_option (_("Appearance/Colors"), new OptionEditorBlank ());
3852
3853         /* Quirks */
3854
3855         OptionEditorHeading* quirks_head = new OptionEditorHeading (_("Various Workarounds for Windowing Systems"));
3856
3857         quirks_head->set_note (string_compose (_("Rules for closing, minimizing, maximizing, and stay-on-top can vary\
3858 with each version of your OS, and the preferences that you've set in your OS.\n\n\
3859 You can adjust the options, below, to change how %1's windows and dialogs behave.\n\n\
3860 These settings will only take effect after %1 is restarted.\n\
3861         "), PROGRAM_NAME));
3862
3863         add_option (_("Appearance/Quirks"), quirks_head);
3864
3865         bo = new BoolOption (
3866                      "use-wm-visibility",
3867                      _("Use visibility information provided by your Window Manager/Desktop"),
3868                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_wm_visibility),
3869                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_wm_visibility)
3870                      );
3871         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget (),
3872                                 _("If you have trouble toggling between hidden Editor and Mixer windows, try changing this setting."));
3873         add_option (_("Appearance/Quirks"), bo);
3874
3875 #ifndef __APPLE__
3876         bo = new BoolOption (
3877                         "all-floating-windows-are-dialogs",
3878                         _("All floating windows are dialogs"),
3879                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_all_floating_windows_are_dialogs),
3880                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_all_floating_windows_are_dialogs)
3881                         );
3882         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget (),
3883                         _("Mark all floating windows to be type \"Dialog\" rather than using \"Utility\" for some.\nThis may help with some window managers."));
3884         add_option (_("Appearance/Quirks"), bo);
3885
3886         bo = new BoolOption (
3887                         "transients-follow-front",
3888                         _("Transient windows follow front window."),
3889                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_transients_follow_front),
3890                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_transients_follow_front)
3891                         );
3892         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget (),
3893                                 _("Make transient windows follow the front window when toggling between the editor and mixer."));
3894         add_option (_("Appearance/Quirks"), bo);
3895 #endif
3896
3897         if (!Profile->get_mixbus()) {
3898                 bo = new BoolOption (
3899                                 "floating-monitor-section",
3900                                 _("Float detached monitor-section window"),
3901                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_floating_monitor_section),
3902                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_floating_monitor_section)
3903                                 );
3904                 Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget (),
3905                                         _("When detaching the monitoring section, mark it as \"Utility\" window to stay in front."));
3906                 add_option (_("Appearance/Quirks"), bo);
3907         }
3908
3909         add_option (_("Appearance/Quirks"), new OptionEditorBlank ());
3910
3911         /* VIDEO Timeline */
3912         add_option (_("Video"), new OptionEditorHeading (_("Video Server")));
3913         add_option (_("Video"), new VideoTimelineOptions (_rc_config));
3914
3915         Widget::show_all ();
3916
3917         //trigger some parameter-changed messages which affect widget-visibility or -sensitivity
3918         parameter_changed ("send-ltc");
3919         parameter_changed ("sync-source");
3920         parameter_changed ("use-monitor-bus");
3921         parameter_changed ("open-gui-after-adding-plugin");
3922
3923         XMLNode* node = ARDOUR_UI::instance()->preferences_settings();
3924         if (node) {
3925                 /* gcc4 complains about ambiguity with Gtk::Widget::set_state
3926                    (Gtk::StateType) here !!!
3927                 */
3928                 Tabbable::set_state (*node, Stateful::loading_state_version);
3929         }
3930
3931         set_current_page (_("General"));
3932 }
3933
3934 void
3935 RCOptionEditor::parameter_changed (string const & p)
3936 {
3937         OptionEditor::parameter_changed (p);
3938
3939         if (p == "use-monitor-bus") {
3940                 bool const s = Config->get_use_monitor_bus ();
3941                 if (!s) {
3942                         /* we can't use this if we don't have a monitor bus */
3943                         Config->set_solo_control_is_listen_control (false);
3944                 }
3945                 _solo_control_is_listen_control->set_sensitive (s);
3946                 _listen_position->set_sensitive (s);
3947         } else if (p == "sync-source") {
3948                 _sync_source->set_sensitive (true);
3949                 if (_session) {
3950                         _sync_source->set_sensitive (!_session->config.get_external_sync());
3951                 }
3952                 switch(Config->get_sync_source()) {
3953                 case ARDOUR::MTC:
3954                 case ARDOUR::LTC:
3955                         _sync_genlock->set_sensitive (true);
3956                         _sync_framerate->set_sensitive (true);
3957                         _sync_source_2997->set_sensitive (true);
3958                         break;
3959                 default:
3960                         _sync_genlock->set_sensitive (false);
3961                         _sync_framerate->set_sensitive (false);
3962                         _sync_source_2997->set_sensitive (false);
3963                         break;
3964                 }
3965         } else if (p == "send-ltc") {
3966                 bool const s = Config->get_send_ltc ();
3967                 _ltc_send_continuously->set_sensitive (s);
3968                 _ltc_volume_slider->set_sensitive (s);
3969         } else if (p == "open-gui-after-adding-plugin" || p == "show-inline-display-by-default") {
3970 #if (defined LV2_SUPPORT && defined LV2_EXTENDED)
3971                 _plugin_prefer_inline->set_sensitive (UIConfiguration::instance().get_open_gui_after_adding_plugin() && UIConfiguration::instance().get_show_inline_display_by_default());
3972 #endif
3973         }
3974 }
3975
3976 void RCOptionEditor::plugin_scan_refresh () {
3977         PluginManager::instance().refresh();
3978 }
3979
3980 void RCOptionEditor::clear_vst_cache () {
3981         PluginManager::instance().clear_vst_cache();
3982 }
3983
3984 void RCOptionEditor::clear_vst_blacklist () {
3985         PluginManager::instance().clear_vst_blacklist();
3986 }
3987
3988 void RCOptionEditor::clear_au_cache () {
3989         PluginManager::instance().clear_au_cache();
3990 }
3991
3992 void RCOptionEditor::clear_au_blacklist () {
3993         PluginManager::instance().clear_au_blacklist();
3994 }
3995
3996 void RCOptionEditor::edit_lxvst_path () {
3997         Glib::RefPtr<Gdk::Window> win = get_parent_window ();
3998         Gtkmm2ext::PathsDialog *pd = new Gtkmm2ext::PathsDialog (
3999                 *current_toplevel(), _("Set Linux VST Search Path"),
4000                 _rc_config->get_plugin_path_lxvst(),
4001                 PluginManager::instance().get_default_lxvst_path()
4002                 );
4003         ResponseType r = (ResponseType) pd->run ();
4004         pd->hide();
4005         if (r == RESPONSE_ACCEPT) {
4006                 _rc_config->set_plugin_path_lxvst(pd->get_serialized_paths());
4007
4008                 MessageDialog msg (_("Re-scan Plugins now?"),
4009                                 false /*no markup*/, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, true /*modal*/);
4010                 msg.set_default_response (Gtk::RESPONSE_YES);
4011                 if (msg.run() == Gtk::RESPONSE_YES) {
4012                         msg.hide ();
4013                         plugin_scan_refresh ();
4014                 }
4015         }
4016         delete pd;
4017 }
4018
4019 void RCOptionEditor::edit_vst_path () {
4020         Gtkmm2ext::PathsDialog *pd = new Gtkmm2ext::PathsDialog (
4021                 *current_toplevel(), _("Set Windows VST Search Path"),
4022                 _rc_config->get_plugin_path_vst(),
4023                 PluginManager::instance().get_default_windows_vst_path()
4024                 );
4025         ResponseType r = (ResponseType) pd->run ();
4026         pd->hide();
4027         if (r == RESPONSE_ACCEPT) {
4028                 _rc_config->set_plugin_path_vst(pd->get_serialized_paths());
4029                 MessageDialog msg (_("Re-scan Plugins now?"),
4030                                 false /*no markup*/, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, true /*modal*/);
4031                 msg.set_default_response (Gtk::RESPONSE_YES);
4032                 if (msg.run() == Gtk::RESPONSE_YES) {
4033                         msg.hide ();
4034                         plugin_scan_refresh ();
4035                 }
4036         }
4037         delete pd;
4038 }
4039
4040
4041 void
4042 RCOptionEditor::populate_sync_options ()
4043 {
4044         vector<SyncSource> sync_opts = ARDOUR::get_available_sync_options ();
4045
4046         _sync_source->clear ();
4047
4048         for (vector<SyncSource>::iterator i = sync_opts.begin(); i != sync_opts.end(); ++i) {
4049                 _sync_source->add (*i, sync_source_to_string (*i));
4050         }
4051
4052         if (sync_opts.empty()) {
4053                 _sync_source->set_sensitive(false);
4054         } else {
4055                 if (std::find(sync_opts.begin(), sync_opts.end(), _rc_config->get_sync_source()) == sync_opts.end()) {
4056                         _rc_config->set_sync_source(sync_opts.front());
4057                 }
4058         }
4059
4060         parameter_changed ("sync-source");
4061 }
4062
4063 Gtk::Window*
4064 RCOptionEditor::use_own_window (bool and_fill_it)
4065 {
4066         bool new_window = !own_window ();
4067
4068         Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
4069
4070         if (win && new_window) {
4071                 win->set_name ("PreferencesWindow");
4072                 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Preferences"), this);
4073                 win->resize (1, 1);
4074                 win->set_resizable (false);
4075         }
4076
4077         return win;
4078 }
4079
4080 XMLNode&
4081 RCOptionEditor::get_state ()
4082 {
4083         XMLNode* node = new XMLNode (X_("Preferences"));
4084         node->add_child_nocopy (Tabbable::get_state());
4085         return *node;
4086 }