Update preferences when Ctrl-surfaces change with session.
[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 speficify 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 unvailable. 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         ComboOption<FadeShape>* fadeshape = new ComboOption<FadeShape> (
2398                         "default-fade-shape",
2399                         _("Default fade shape"),
2400                         sigc::mem_fun (*_rc_config,
2401                                 &RCConfiguration::get_default_fade_shape),
2402                         sigc::mem_fun (*_rc_config,
2403                                 &RCConfiguration::set_default_fade_shape)
2404                         );
2405
2406         fadeshape->add (FadeLinear,
2407                         _("Linear (for highly correlated material)"));
2408         fadeshape->add (FadeConstantPower, _("Constant power"));
2409         fadeshape->add (FadeSymmetric, _("Symmetric"));
2410         fadeshape->add (FadeSlow, _("Slow"));
2411         fadeshape->add (FadeFast, _("Fast"));
2412
2413         add_option (_("Editor"), fadeshape);
2414
2415         bco = new BoolComboOption (
2416                      "use-overlap-equivalency",
2417                      _("Regions in edit groups are edited together"),
2418                      _("whenever they overlap in time"),
2419                      _("only if they have identical length and position"),
2420                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_use_overlap_equivalency),
2421                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_use_overlap_equivalency)
2422                      );
2423
2424         add_option (_("Editor"), bco);
2425
2426         ComboOption<LayerModel>* lm = new ComboOption<LayerModel> (
2427                 "layer-model",
2428                 _("Layering model"),
2429                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_layer_model),
2430                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_layer_model)
2431                 );
2432
2433         lm->add (LaterHigher, _("later is higher"));
2434         lm->add (Manual, _("manual layering"));
2435         add_option (_("Editor"), lm);
2436
2437         ComboOption<RegionSelectionAfterSplit> *rsas = new ComboOption<RegionSelectionAfterSplit> (
2438                     "region-selection-after-split",
2439                     _("After splitting selected regions, select"),
2440                     sigc::mem_fun (*_rc_config, &RCConfiguration::get_region_selection_after_split),
2441                     sigc::mem_fun (*_rc_config, &RCConfiguration::set_region_selection_after_split));
2442
2443         // TODO: decide which of these modes are really useful
2444         rsas->add(None, _("no regions"));
2445         // rsas->add(NewlyCreatedLeft, _("newly-created regions before the split"));
2446         // rsas->add(NewlyCreatedRight, _("newly-created regions after the split"));
2447         rsas->add(NewlyCreatedBoth, _("newly-created regions"));
2448         // rsas->add(Existing, _("unmodified regions in the existing selection"));
2449         // rsas->add(ExistingNewlyCreatedLeft, _("existing selection and newly-created regions before the split"));
2450         // rsas->add(ExistingNewlyCreatedRight, _("existing selection and newly-created regions after the split"));
2451         rsas->add(ExistingNewlyCreatedBoth, _("existing selection and newly-created regions"));
2452
2453         add_option (_("Editor"), rsas);
2454
2455         add_option (_("Editor/Modifiers"), new OptionEditorHeading (_("Keyboard Modifiers")));
2456         add_option (_("Editor/Modifiers"), new KeyboardOptions);
2457         add_option (_("Editor/Modifiers"), new OptionEditorBlank ());
2458
2459         /* MIXER -- SOLO AND MUTE */
2460
2461         add_option (_("Mixer"), new OptionEditorHeading (_("Solo")));
2462
2463         _solo_control_is_listen_control = new BoolOption (
2464                 "solo-control-is-listen-control",
2465                 _("Solo controls are Listen controls"),
2466                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_control_is_listen_control),
2467                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_control_is_listen_control)
2468                 );
2469
2470         add_option (_("Mixer"), _solo_control_is_listen_control);
2471
2472         add_option (_("Mixer"),
2473              new BoolOption (
2474                      "exclusive-solo",
2475                      _("Exclusive solo"),
2476                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_exclusive_solo),
2477                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_exclusive_solo)
2478                      ));
2479
2480         add_option (_("Mixer"),
2481              new BoolOption (
2482                      "show-solo-mutes",
2483                      _("Show solo muting"),
2484                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_show_solo_mutes),
2485                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_solo_mutes)
2486                      ));
2487
2488         add_option (_("Mixer"),
2489              new BoolOption (
2490                      "solo-mute-override",
2491                      _("Soloing overrides muting"),
2492                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_override),
2493                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_override)
2494                      ));
2495
2496         add_option (_("Mixer"),
2497              new FaderOption (
2498                      "solo-mute-gain",
2499                      _("Solo-in-place mute cut (dB)"),
2500                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_gain),
2501                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_gain)
2502                      ));
2503
2504         _listen_position = new ComboOption<ListenPosition> (
2505                 "listen-position",
2506                 _("Listen Position"),
2507                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_listen_position),
2508                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_listen_position)
2509                 );
2510
2511         _listen_position->add (AfterFaderListen, _("after-fader (AFL)"));
2512         _listen_position->add (PreFaderListen, _("pre-fader (PFL)"));
2513
2514         add_option (_("Mixer"), _listen_position);
2515
2516         ComboOption<PFLPosition>* pp = new ComboOption<PFLPosition> (
2517                 "pfl-position",
2518                 _("PFL signals come from"),
2519                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_pfl_position),
2520                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_pfl_position)
2521                 );
2522
2523         pp->add (PFLFromBeforeProcessors, _("before pre-fader processors"));
2524         pp->add (PFLFromAfterProcessors, _("pre-fader but after pre-fader processors"));
2525
2526         add_option (_("Mixer"), pp);
2527
2528         ComboOption<AFLPosition>* pa = new ComboOption<AFLPosition> (
2529                 "afl-position",
2530                 _("AFL signals come from"),
2531                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_afl_position),
2532                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_afl_position)
2533                 );
2534
2535         pa->add (AFLFromBeforeProcessors, _("immediately post-fader"));
2536         pa->add (AFLFromAfterProcessors, _("after post-fader processors (before pan)"));
2537
2538         add_option (_("Mixer"), pa);
2539
2540         add_option (_("Mixer"), new OptionEditorHeading (_("Default Track / Bus Muting Options")));
2541
2542         add_option (_("Mixer"),
2543              new BoolOption (
2544                      "mute-affects-pre-fader",
2545                      _("Mute affects pre-fader sends"),
2546                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_pre_fader),
2547                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_pre_fader)
2548                      ));
2549
2550         add_option (_("Mixer"),
2551              new BoolOption (
2552                      "mute-affects-post-fader",
2553                      _("Mute affects post-fader sends"),
2554                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_post_fader),
2555                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_post_fader)
2556                      ));
2557
2558         add_option (_("Mixer"),
2559              new BoolOption (
2560                      "mute-affects-control-outs",
2561                      _("Mute affects control outputs"),
2562                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_control_outs),
2563                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_control_outs)
2564                      ));
2565
2566         add_option (_("Mixer"),
2567              new BoolOption (
2568                      "mute-affects-main-outs",
2569                      _("Mute affects main outputs"),
2570                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_main_outs),
2571                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_main_outs)
2572                      ));
2573
2574
2575         if (!ARDOUR::Profile->get_mixbus()) {
2576                 add_option (_("Mixer"), new OptionEditorHeading (_("Send Routing")));
2577                 add_option (_("Mixer"),
2578                                 new BoolOption (
2579                                         "link-send-and-route-panner",
2580                                         _("Link panners of Aux and External Sends with main panner by default"),
2581                                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_link_send_and_route_panner),
2582                                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_link_send_and_route_panner)
2583                                         ));
2584         }
2585
2586         /* Signal Flow */
2587
2588         add_option (_("Signal Flow"), new OptionEditorHeading (_("Monitoring")));
2589
2590         ComboOption<MonitorModel>* mm = new ComboOption<MonitorModel> (
2591                 "monitoring-model",
2592                 _("Record monitoring handled by"),
2593                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_monitoring_model),
2594                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_monitoring_model)
2595                 );
2596
2597         if (AudioEngine::instance()->port_engine().can_monitor_input()) {
2598                 mm->add (HardwareMonitoring, _("via Audio Driver"));
2599         }
2600
2601         string prog (PROGRAM_NAME);
2602         boost::algorithm::to_lower (prog);
2603         mm->add (SoftwareMonitoring, string_compose (_("%1"), prog));
2604         mm->add (ExternalMonitoring, _("audio hardware"));
2605
2606         add_option (_("Signal Flow"), mm);
2607
2608         bo = new BoolOption (
2609                      "tape-machine-mode",
2610                      _("Tape machine mode"),
2611                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_tape_machine_mode),
2612                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_tape_machine_mode)
2613                      );
2614         add_option (_("Signal Flow"), bo);
2615         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2616                         string_compose (_("<b>When enabled</b> %1 will not monitor a track's input if the transport is stopped."),
2617                                         PROGRAM_NAME));
2618
2619         if (!Profile->get_mixbus()) {
2620
2621                 add_option (_("Signal Flow"), new OptionEditorHeading (_("Track and Bus Connections")));
2622
2623                 add_option (_("Signal Flow"),
2624                                 new BoolOption (
2625                                         "auto-connect-standard-busses",
2626                                         _("Auto-connect master/monitor busses"),
2627                                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_connect_standard_busses),
2628                                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_connect_standard_busses)
2629                                         ));
2630
2631                 ComboOption<AutoConnectOption>* iac = new ComboOption<AutoConnectOption> (
2632                                 "input-auto-connect",
2633                                 _("Connect track inputs"),
2634                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_input_auto_connect),
2635                                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_input_auto_connect)
2636                                 );
2637
2638                 iac->add (AutoConnectPhysical, _("automatically to physical inputs"));
2639                 iac->add (ManualConnect, _("manually"));
2640
2641                 add_option (_("Signal Flow"), iac);
2642
2643                 ComboOption<AutoConnectOption>* oac = new ComboOption<AutoConnectOption> (
2644                                 "output-auto-connect",
2645                                 _("Connect track and bus outputs"),
2646                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_output_auto_connect),
2647                                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_output_auto_connect)
2648                                 );
2649
2650                 oac->add (AutoConnectPhysical, _("automatically to physical outputs"));
2651                 oac->add (AutoConnectMaster, _("automatically to master bus"));
2652                 oac->add (ManualConnect, _("manually"));
2653
2654                 add_option (_("Signal Flow"), oac);
2655
2656                 bo = new BoolOption (
2657                                 "strict-io",
2658                                 _("Use 'Strict-I/O' for new tracks or busses"),
2659                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_strict_io),
2660                                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_strict_io)
2661                                 );
2662
2663                 add_option (_("Signal Flow"), bo);
2664                 Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2665                                 _("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."));
2666
2667         }  // !mixbus
2668
2669
2670         /* AUDIO */
2671
2672         add_option (_("Audio"), new OptionEditorHeading (_("Buffering")));
2673
2674         add_option (_("Audio"), new BufferingOptions (_rc_config));
2675
2676         add_option (_("Audio"), new OptionEditorHeading (_("Denormals")));
2677
2678         add_option (_("Audio"),
2679              new BoolOption (
2680                      "denormal-protection",
2681                      _("Use DC bias to protect against denormals"),
2682                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_protection),
2683                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_protection)
2684                      ));
2685
2686         ComboOption<DenormalModel>* dm = new ComboOption<DenormalModel> (
2687                 "denormal-model",
2688                 _("Processor handling"),
2689                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_model),
2690                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_model)
2691                 );
2692
2693         int dmsize = 1;
2694         dm->add (DenormalNone, _("no processor handling"));
2695
2696         FPU* fpu = FPU::instance();
2697
2698         if (fpu->has_flush_to_zero()) {
2699                 ++dmsize;
2700                 dm->add (DenormalFTZ, _("use FlushToZero"));
2701         } else if (_rc_config->get_denormal_model() == DenormalFTZ) {
2702                 _rc_config->set_denormal_model(DenormalNone);
2703         }
2704
2705         if (fpu->has_denormals_are_zero()) {
2706                 ++dmsize;
2707                 dm->add (DenormalDAZ, _("use DenormalsAreZero"));
2708         } else if (_rc_config->get_denormal_model() == DenormalDAZ) {
2709                 _rc_config->set_denormal_model(DenormalNone);
2710         }
2711
2712         if (fpu->has_flush_to_zero() && fpu->has_denormals_are_zero()) {
2713                 ++dmsize;
2714                 dm->add (DenormalFTZDAZ, _("use FlushToZero and DenormalsAreZero"));
2715         } else if (_rc_config->get_denormal_model() == DenormalFTZDAZ) {
2716                 _rc_config->set_denormal_model(DenormalNone);
2717         }
2718
2719         if (dmsize == 1) {
2720                 dm->set_sensitive(false);
2721         }
2722
2723         add_option (_("Audio"), dm);
2724
2725         add_option (_("Audio"), new OptionEditorHeading (_("Regions")));
2726
2727         add_option (_("Audio"),
2728              new BoolOption (
2729                      "auto-analyse-audio",
2730                      _("Enable automatic analysis of audio"),
2731                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_analyse_audio),
2732                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_analyse_audio)
2733                      ));
2734
2735         add_option (_("Audio"),
2736              new BoolOption (
2737                      "replicate-missing-region-channels",
2738                      _("Replicate missing region channels"),
2739                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_replicate_missing_region_channels),
2740                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_replicate_missing_region_channels)
2741                      ));
2742
2743         /* MIDI */
2744
2745         add_option (_("MIDI"), new OptionEditorHeading (_("Buffering")));
2746
2747         add_option (_("MIDI"),
2748                     new SpinOption<float> (
2749                             "midi-readahead",
2750                             _("MIDI read-ahead time (seconds)"),
2751                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_readahead),
2752                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_readahead),
2753                             0.1, 10, 0.05, 1,
2754                             "", 1.0, 2
2755                             ));
2756
2757         add_option (_("MIDI"), new OptionEditorHeading (_("Session")));
2758
2759         add_option (_("MIDI"),
2760              new SpinOption<int32_t> (
2761                      "initial-program-change",
2762                      _("Initial program change"),
2763                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_initial_program_change),
2764                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_initial_program_change),
2765                      -1, 65536, 1, 10
2766                      ));
2767
2768         add_option (_("MIDI"), new OptionEditorHeading (_("Audition")));
2769
2770         add_option (_("MIDI"),
2771              new BoolOption (
2772                      "sound-midi-notes",
2773                      _("Sound MIDI notes as they are selected in the editor"),
2774                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_sound_midi_notes),
2775                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_sound_midi_notes)
2776                      ));
2777
2778         ComboOption<std::string>* audition_synth = new ComboOption<std::string> (
2779                 "midi-audition-synth-uri",
2780                 _("MIDI Audition Synth (LV2)"),
2781                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_audition_synth_uri),
2782                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_audition_synth_uri)
2783                 );
2784
2785         audition_synth->add(X_(""), _("None"));
2786         PluginInfoList all_plugs;
2787         PluginManager& manager (PluginManager::instance());
2788 #ifdef LV2_SUPPORT
2789         all_plugs.insert (all_plugs.end(), manager.lv2_plugin_info().begin(), manager.lv2_plugin_info().end());
2790
2791         for (PluginInfoList::const_iterator i = all_plugs.begin(); i != all_plugs.end(); ++i) {
2792                 if (manager.get_status (*i) == PluginManager::Hidden) continue;
2793                 if (!(*i)->is_instrument()) continue;
2794                 if ((*i)->type != ARDOUR::LV2) continue;
2795                 if ((*i)->name.length() > 46) {
2796                         audition_synth->add((*i)->unique_id, (*i)->name.substr (0, 44) + "...");
2797                 } else {
2798                         audition_synth->add((*i)->unique_id, (*i)->name);
2799                 }
2800         }
2801 #endif
2802
2803         add_option (_("MIDI"), audition_synth);
2804
2805         /* Click */
2806
2807         add_option (_("Metronome"), new OptionEditorHeading (_("Metronome")));
2808         add_option (_("Metronome"), new ClickOptions (_rc_config));
2809         add_option (_("Metronome"), new OptionEditorHeading (_("Options")));
2810
2811         bo = new BoolOption (
2812                         "click-record-only",
2813                         _("Enable metronome only while recording"),
2814                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_click_record_only),
2815                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_click_record_only)
2816                         );
2817
2818         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2819                         string_compose (_("<b>When enabled</b> the metronome will remain silent if %1 is <b>not recording</b>."), PROGRAM_NAME));
2820         add_option (_("Metronome"), bo);
2821         add_option (_("Metronome"), new OptionEditorBlank ());
2822
2823
2824         /* Meters */
2825
2826         add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Metering")));
2827
2828         ComboOption<float>* mht = new ComboOption<float> (
2829                 "meter-hold",
2830                 _("Peak hold time"),
2831                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_hold),
2832                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_hold)
2833                 );
2834
2835         mht->add (MeterHoldOff, _("off"));
2836         mht->add (MeterHoldShort, _("short"));
2837         mht->add (MeterHoldMedium, _("medium"));
2838         mht->add (MeterHoldLong, _("long"));
2839
2840         add_option (S_("Preferences|Metering"), mht);
2841
2842         ComboOption<float>* mfo = new ComboOption<float> (
2843                 "meter-falloff",
2844                 _("DPM fall-off"),
2845                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_falloff),
2846                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_falloff)
2847                 );
2848
2849         mfo->add (METER_FALLOFF_OFF,      _("off"));
2850         mfo->add (METER_FALLOFF_SLOWEST,  _("slowest [6.6dB/sec]"));
2851         mfo->add (METER_FALLOFF_SLOW,     _("slow [8.6dB/sec] (BBC PPM, EBU PPM)"));
2852         mfo->add (METER_FALLOFF_SLOWISH,  _("moderate [12.0dB/sec] (DIN)"));
2853         mfo->add (METER_FALLOFF_MODERATE, _("medium [13.3dB/sec] (EBU Digi PPM, IRT Digi PPM)"));
2854         mfo->add (METER_FALLOFF_MEDIUM,   _("fast [20dB/sec]"));
2855         mfo->add (METER_FALLOFF_FAST,     _("very fast [32dB/sec]"));
2856
2857         add_option (S_("Preferences|Metering"), mfo);
2858
2859         ComboOption<MeterLineUp>* mlu = new ComboOption<MeterLineUp> (
2860                 "meter-line-up-level",
2861                 _("Meter line-up level; 0dBu"),
2862                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_line_up_level),
2863                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_line_up_level)
2864                 );
2865
2866         mlu->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
2867         mlu->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
2868         mlu->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
2869         mlu->add (MeteringLineUp15, _("-15dBFS (DIN)"));
2870
2871         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."));
2872
2873         add_option (S_("Preferences|Metering"), mlu);
2874
2875         ComboOption<MeterLineUp>* mld = new ComboOption<MeterLineUp> (
2876                 "meter-line-up-din",
2877                 _("IEC1/DIN Meter line-up level; 0dBu"),
2878                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_line_up_din),
2879                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_line_up_din)
2880                 );
2881
2882         mld->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
2883         mld->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
2884         mld->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
2885         mld->add (MeteringLineUp15, _("-15dBFS (DIN)"));
2886
2887         Gtkmm2ext::UI::instance()->set_tip (mld->tip_widget(), _("Reference level for IEC1/DIN meter."));
2888
2889         add_option (S_("Preferences|Metering"), mld);
2890
2891         ComboOption<VUMeterStandard>* mvu = new ComboOption<VUMeterStandard> (
2892                 "meter-vu-standard",
2893                 _("VU Meter standard"),
2894                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_vu_standard),
2895                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_vu_standard)
2896                 );
2897
2898         mvu->add (MeteringVUfrench,   _("0VU = -2dBu (France)"));
2899         mvu->add (MeteringVUamerican, _("0VU = 0dBu (North America, Australia)"));
2900         mvu->add (MeteringVUstandard, _("0VU = +4dBu (standard)"));
2901         mvu->add (MeteringVUeight,    _("0VU = +8dBu"));
2902
2903         add_option (S_("Preferences|Metering"), mvu);
2904
2905         HSliderOption *mpks = new HSliderOption("meter-peak",
2906                         _("Peak indicator threshold [dBFS]"),
2907                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_peak),
2908                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_peak),
2909                         -10, 0, .1, .1
2910                         );
2911
2912         Gtkmm2ext::UI::instance()->set_tip (
2913                         mpks->tip_widget(),
2914                         _("Specify the audio signal level in dBFS at and above which the meter-peak indicator will flash red."));
2915
2916         add_option (S_("Preferences|Metering"), mpks);
2917
2918         OptionEditorHeading* default_meter_head = new OptionEditorHeading (_("Default Meter Types"));
2919         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."));
2920
2921         add_option (S_("Preferences|Metering"), default_meter_head);
2922
2923         ComboOption<MeterType>* mtm = new ComboOption<MeterType> (
2924                 "meter-type-master",
2925                 _("Default Meter Type for Master Bus"),
2926                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_master),
2927                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_master)
2928                 );
2929         mtm->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
2930         mtm->add (MeterK20,     ArdourMeter::meter_type_string(MeterK20));
2931         mtm->add (MeterK14,     ArdourMeter::meter_type_string(MeterK14));
2932         mtm->add (MeterK12,     ArdourMeter::meter_type_string(MeterK12));
2933         mtm->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
2934         mtm->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
2935         mtm->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
2936         mtm->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
2937
2938         add_option (S_("Preferences|Metering"), mtm);
2939
2940
2941         ComboOption<MeterType>* mtb = new ComboOption<MeterType> (
2942                 "meter-type-bus",
2943                 _("Default meter type for busses"),
2944                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_bus),
2945                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_bus)
2946                 );
2947         mtb->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
2948         mtb->add (MeterK20,     ArdourMeter::meter_type_string(MeterK20));
2949         mtb->add (MeterK14,     ArdourMeter::meter_type_string(MeterK14));
2950         mtb->add (MeterK12,     ArdourMeter::meter_type_string(MeterK12));
2951         mtb->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
2952         mtb->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
2953         mtb->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
2954         mtb->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
2955
2956         add_option (S_("Preferences|Metering"), mtb);
2957
2958         ComboOption<MeterType>* mtt = new ComboOption<MeterType> (
2959                 "meter-type-track",
2960                 _("Default meter type for tracks"),
2961                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_track),
2962                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_track)
2963                 );
2964         mtt->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
2965         mtt->add (MeterPeak0dB, ArdourMeter::meter_type_string(MeterPeak0dB));
2966
2967         add_option (S_("Preferences|Metering"), mtt);
2968
2969         add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Post Export Analysis")));
2970
2971         add_option (S_("Preferences|Metering"),
2972              new BoolOption (
2973                      "save-export-analysis-image",
2974                      _("Save loudness analysis as image file"),
2975                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_save_export_analysis_image),
2976                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_save_export_analysis_image)
2977                      ));
2978
2979         /* TRANSPORT & Sync */
2980
2981         add_option (_("Transport"), new OptionEditorHeading (_("General")));
2982
2983         bo = new BoolOption (
2984                      "stop-at-session-end",
2985                      _("Stop at the end of the session"),
2986                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_at_session_end),
2987                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_at_session_end)
2988                      );
2989         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
2990                                             string_compose (_("<b>When enabled</b> if %1 is <b>not recording</b>, it will stop the transport "
2991                                                               "when it reaches the current session end marker\n\n"
2992                                                               "<b>When disabled</b> %1 will continue to roll past the session end marker at all times"),
2993                                                             PROGRAM_NAME));
2994         add_option (_("Transport"), bo);
2995
2996         bo = new BoolOption (
2997                      "latched-record-enable",
2998                      _("Keep record-enable engaged on stop"),
2999                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_latched_record_enable),
3000                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_latched_record_enable)
3001                      );
3002         add_option (_("Transport"), bo);
3003         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3004                         _("<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."));
3005
3006         bo = new BoolOption (
3007                      "disable-disarm-during-roll",
3008                      _("Disable per-track record disarm while rolling"),
3009                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_disable_disarm_during_roll),
3010                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_disable_disarm_during_roll)
3011                      );
3012         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."));
3013         add_option (_("Transport"), bo);
3014
3015         bo = new BoolOption (
3016                      "quieten_at_speed",
3017                      _("12dB gain reduction during fast-forward and fast-rewind"),
3018                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_quieten_at_speed),
3019                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_quieten_at_speed)
3020                      );
3021         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3022                         _("<b>When enabled</b> rhis will reduce the unpleasant increase in perceived volume "
3023                                 "that occurs when fast-forwarding or rewinding through some kinds of audio"));
3024         add_option (_("Transport"), bo);
3025
3026         ComboOption<float>* psc = new ComboOption<float> (
3027                      "preroll-seconds",
3028                      _("Preroll"),
3029                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_preroll_seconds),
3030                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_preroll_seconds)
3031                      );
3032         Gtkmm2ext::UI::instance()->set_tip (psc->tip_widget(),
3033                                             (_("The amount of preroll to apply when <b>Play with Preroll</b> or <b>Record with Preroll</b>is initiated.\n\n"
3034                                                "If <b>Follow Edits</b> is enabled, the preroll is applied to the playhead position when a region is selected or trimmed.")));
3035         psc->add (-4.0, _("4 Bars"));
3036         psc->add (-2.0, _("2 Bars"));
3037         psc->add (-1.0, _("1 Bar"));
3038         psc->add (0.0, _("0 (no pre-roll)"));
3039         psc->add (0.1, _("0.1 second"));
3040         psc->add (0.25, _("0.25 second"));
3041         psc->add (0.5, _("0.5 second"));
3042         psc->add (1.0, _("1.0 second"));
3043         psc->add (2.0, _("2.0 seconds"));
3044         add_option (_("Transport"), psc);
3045
3046
3047         add_option (_("Transport"), new OptionEditorHeading (_("Looping")));
3048
3049         bo = new BoolOption (
3050                      "loop-is-mode",
3051                      _("Play loop is a transport mode"),
3052                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_loop_is_mode),
3053                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_loop_is_mode)
3054                      );
3055         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3056                                             (_("<b>When enabled</b> the loop button does not start playback but forces playback to always play the loop\n\n"
3057                                                "<b>When disabled</b> the loop button starts playing the loop, but stop then cancels loop playback")));
3058         add_option (_("Transport"), bo);
3059
3060         bo = new BoolOption (
3061                      "seamless-loop",
3062                      _("Do seamless looping (not possible when slaved to MTC, LTC etc)"),
3063                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_seamless_loop),
3064                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_seamless_loop)
3065                      );
3066         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3067                                             string_compose (_("<b>When enabled</b> this will loop by reading ahead and wrapping around at the loop point, "
3068                                                               "preventing any need to do a transport locate at the end of the loop\n\n"
3069                                                               "<b>When disabled</b> looping is done by locating back to the start of the loop when %1 reaches the end "
3070                                                               "which will often cause a small click or delay"), PROGRAM_NAME));
3071         add_option (_("Transport"), bo);
3072
3073         add_option (_("Transport"), new OptionEditorHeading (_("Dropout (xrun) Handling")));
3074         bo = new BoolOption (
3075                      "stop-recording-on-xrun",
3076                      _("Stop recording when an xrun occurs"),
3077                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_recording_on_xrun),
3078                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_recording_on_xrun)
3079                      );
3080         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3081                                             string_compose (_("<b>When enabled</b> %1 will stop recording if an over- or underrun is detected by the audio engine"),
3082                                                             PROGRAM_NAME));
3083         add_option (_("Transport"), bo);
3084
3085         bo = new BoolOption (
3086                      "create-xrun-marker",
3087                      _("Create markers where xruns occur"),
3088                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_create_xrun_marker),
3089                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_create_xrun_marker)
3090                      );
3091         add_option (_("Transport"), bo);
3092
3093
3094         /* SYNC */
3095
3096         add_option (_("Sync"), new OptionEditorHeading (_("External Syncronization")));
3097
3098         _sync_source = new ComboOption<SyncSource> (
3099                 "sync-source",
3100                 _("External timecode source"),
3101                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_sync_source),
3102                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_sync_source)
3103                 );
3104
3105         add_option (_("Sync"), _sync_source);
3106
3107         _sync_framerate = new BoolOption (
3108                      "timecode-sync-frame-rate",
3109                      _("Match session video frame rate to external timecode"),
3110                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_sync_frame_rate),
3111                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_sync_frame_rate)
3112                      );
3113         Gtkmm2ext::UI::instance()->set_tip
3114                 (_sync_framerate->tip_widget(),
3115                  string_compose (_("This option controls the value of the video frame rate <i>while chasing</i> an external timecode source.\n\n"
3116                                    "<b>When enabled</b> the session video frame rate will be changed to match that of the selected external timecode source.\n\n"
3117                                    "<b>When disabled</b> the session video frame rate will not be changed to match that of the selected external timecode source."
3118                                    "Instead the frame rate indication in the main clock will flash red and %1 will convert between the external "
3119                                    "timecode standard and the session standard."), PROGRAM_NAME));
3120
3121         add_option (_("Sync"), _sync_framerate);
3122
3123         _sync_genlock = new BoolOption (
3124                 "timecode-source-is-synced",
3125                 _("Sync-lock timecode to clock (disable drift compensation)"),
3126                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_is_synced),
3127                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_is_synced)
3128                 );
3129         Gtkmm2ext::UI::instance()->set_tip
3130                 (_sync_genlock->tip_widget(),
3131                  string_compose (_("<b>When enabled</b> %1 will never varispeed when slaved to external timecode. "
3132                                    "Sync Lock indicates that the selected external timecode source shares clock-sync "
3133                                    "(Black &amp; Burst, Wordclock, etc) with the audio interface. "
3134                                    "This option disables drift compensation. The transport speed is fixed at 1.0. "
3135                                    "Vari-speed LTC will be ignored and cause drift."
3136                                    "\n\n"
3137                                    "<b>When disabled</b> %1 will compensate for potential drift, regardless if the "
3138                                    "timecode sources shares clock sync."
3139                                   ), PROGRAM_NAME));
3140
3141
3142         add_option (_("Sync"), _sync_genlock);
3143
3144         _sync_source_2997 = new BoolOption (
3145                 "timecode-source-2997",
3146                 _("Lock to 29.9700 fps instead of 30000/1001"),
3147                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_2997),
3148                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_2997)
3149                 );
3150         Gtkmm2ext::UI::instance()->set_tip
3151                 (_sync_source_2997->tip_widget(),
3152                  _("<b>When enabled</b> the external timecode source is assumed to use 29.97 fps instead of 30000/1001.\n"
3153                          "SMPTE 12M-1999 specifies 29.97df as 30000/1001. The spec further mentions that "
3154                          "drop-frame timecode has an accumulated error of -86ms over a 24-hour period.\n"
3155                          "Drop-frame timecode would compensate exactly for a NTSC color frame rate of 30 * 0.9990 (ie 29.970000). "
3156                          "That is not the actual rate. However, some vendors use that rate - despite it being against the specs - "
3157                          "because the variant of using exactly 29.97 fps has zero timecode drift.\n"
3158                          ));
3159
3160         add_option (_("Sync"), _sync_source_2997);
3161
3162         add_option (_("Sync/LTC"), new OptionEditorHeading (_("Linear Timecode (LTC) Reader")));
3163
3164         _ltc_port = new ComboStringOption (
3165                 "ltc-source-port",
3166                 _("LTC incoming port"),
3167                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_source_port),
3168                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_source_port)
3169                 );
3170
3171         vector<string> physical_inputs;
3172         physical_inputs.push_back (_("None"));
3173         AudioEngine::instance()->get_physical_inputs (DataType::AUDIO, physical_inputs);
3174         _ltc_port->set_popdown_strings (physical_inputs);
3175
3176         populate_sync_options ();
3177         AudioEngine::instance()->Running.connect (engine_started_connection, MISSING_INVALIDATOR, boost::bind (&RCOptionEditor::populate_sync_options, this), gui_context());
3178
3179         add_option (_("Sync/LTC"), _ltc_port);
3180
3181         add_option (_("Sync/LTC"), new OptionEditorHeading (_("Linear Timecode (LTC) Generator")));
3182
3183         add_option (_("Sync/LTC"),
3184                     new BoolOption (
3185                             "send-ltc",
3186                             _("Enable LTC generator"),
3187                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_ltc),
3188                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_ltc)
3189                             ));
3190
3191         _ltc_send_continuously = new BoolOption (
3192                             "ltc-send-continuously",
3193                             _("Send LTC while stopped"),
3194                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_send_continuously),
3195                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_send_continuously)
3196                             );
3197         Gtkmm2ext::UI::instance()->set_tip
3198                 (_ltc_send_continuously->tip_widget(),
3199                  string_compose (_("<b>When enabled</b> %1 will continue to send LTC information even when the transport (playhead) is not moving"), PROGRAM_NAME));
3200         add_option (_("Sync/LTC"), _ltc_send_continuously);
3201
3202         _ltc_volume_slider = new HSliderOption("ltcvol", _("LTC generator level [dBFS]"),
3203                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_output_volume),
3204                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_output_volume),
3205                                         -50, 0, .5, 5,
3206                                         .05, true);
3207
3208         Gtkmm2ext::UI::instance()->set_tip
3209                 (_ltc_volume_slider->tip_widget(),
3210                  _("Specify the Peak Volume of the generated LTC signal in dBFS. A good value is  0dBu ^= -18dBFS in an EBU calibrated system"));
3211
3212         add_option (_("Sync/LTC"), _ltc_volume_slider);
3213
3214
3215         add_option (_("Sync/MIDI"), new OptionEditorHeading (_("MIDI Beat Clock (Mclk) Generator")));
3216
3217         add_option (_("Sync/MIDI"),
3218                     new BoolOption (
3219                             "send-midi-clock",
3220                             _("Enable Mclk generator"),
3221                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_midi_clock),
3222                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_midi_clock)
3223                             ));
3224
3225         add_option (_("Sync/MIDI"), new OptionEditorHeading (_("MIDI Time Code (MTC) Generator")));
3226
3227         add_option (_("Sync/MIDI"),
3228                     new BoolOption (
3229                             "send-mtc",
3230                             _("Enable MTC Generator"),
3231                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mtc),
3232                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mtc)
3233                             ));
3234
3235         add_option (_("Sync/MIDI"),
3236                     new SpinOption<int> (
3237                             "mtc-qf-speed-tolerance",
3238                             _("Percentage either side of normal transport speed to transmit MTC"),
3239                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mtc_qf_speed_tolerance),
3240                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mtc_qf_speed_tolerance),
3241                             0, 20, 1, 5
3242                             ));
3243
3244         add_option (_("Sync/MIDI"), new OptionEditorHeading (_("MIDI Machine Control (MMC)")));
3245
3246         add_option (_("Sync/MIDI"),
3247                     new BoolOption (
3248                             "mmc-control",
3249                             _("Respond to MMC commands"),
3250                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_control),
3251                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_control)
3252                             ));
3253
3254         add_option (_("Sync/MIDI"),
3255                     new BoolOption (
3256                             "send-mmc",
3257                             _("Send MMC commands"),
3258                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mmc),
3259                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mmc)
3260                             ));
3261
3262         add_option (_("Sync/MIDI"),
3263              new SpinOption<uint8_t> (
3264                      "mmc-receive-device-id",
3265                      _("Inbound MMC device ID"),
3266                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_receive_device_id),
3267                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_receive_device_id),
3268                      0, 128, 1, 10
3269                      ));
3270
3271         add_option (_("Sync/MIDI"),
3272              new SpinOption<uint8_t> (
3273                      "mmc-send-device-id",
3274                      _("Outbound MMC device ID"),
3275                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_send_device_id),
3276                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_send_device_id),
3277                      0, 128, 1, 10
3278                      ));
3279
3280
3281         /* Control Surfaces */
3282
3283         add_option (_("Control Surfaces"), new OptionEditorHeading (_("Control Surfaces")));
3284         add_option (_("Control Surfaces"), new ControlSurfacesOptions ());
3285
3286         /* MIDI PORTs */
3287         add_option (_("MIDI Ports"), new OptionEditorHeading (_("MIDI Port Options")));
3288
3289         add_option (_("MIDI Ports"),
3290                     new BoolOption (
3291                             "get-midi-input-follows-selection",
3292                             _("MIDI input follows MIDI track selection"),
3293                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_input_follows_selection),
3294                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_input_follows_selection)
3295                             ));
3296
3297         add_option (_("MIDI Ports"), new MidiPortOptions ());
3298         add_option (_("MIDI Ports"), new OptionEditorBlank ());
3299
3300         /* PLUGINS */
3301
3302 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT || defined AUDIOUNIT_SUPPORT)
3303         add_option (_("Plugins"), new OptionEditorHeading (_("Scan/Discover")));
3304         add_option (_("Plugins"),
3305                         new RcActionButton (_("Scan for Plugins"),
3306                                 sigc::mem_fun (*this, &RCOptionEditor::plugin_scan_refresh)));
3307
3308 #endif
3309
3310         add_option (_("Plugins"), new OptionEditorHeading (_("General")));
3311
3312 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT || defined AUDIOUNIT_SUPPORT)
3313         bo = new BoolOption (
3314                         "show-plugin-scan-window",
3315                         _("Always Display Plugin Scan Progress"),
3316                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_plugin_scan_window),
3317                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_plugin_scan_window)
3318                         );
3319         add_option (_("Plugins"), bo);
3320         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3321                         _("<b>When enabled</b> a popup window showing plugin scan progress is displayed for indexing (cache load) and discovery (detect new plugins)"));
3322 #endif
3323
3324         bo = new BoolOption (
3325                 "plugins-stop-with-transport",
3326                 _("Silence plugins when the transport is stopped"),
3327                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugins_stop_with_transport),
3328                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_plugins_stop_with_transport)
3329                 );
3330         add_option (_("Plugins"), bo);
3331         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3332                                             _("<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."));
3333
3334         bo = new BoolOption (
3335                 "new-plugins-active",
3336                         _("Make new plugins active"),
3337                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_new_plugins_active),
3338                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_new_plugins_active)
3339                         );
3340         add_option (_("Plugins"), bo);
3341         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3342                                             _("<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"));
3343
3344 #if (defined WINDOWS_VST_SUPPORT || defined MACVST_SUPPORT || defined LXVST_SUPPORT)
3345         add_option (_("Plugins/VST"), new OptionEditorHeading (_("VST")));
3346 #if 0
3347         add_option (_("Plugins/VST"),
3348                         new RcActionButton (_("Scan for Plugins"),
3349                                 sigc::mem_fun (*this, &RCOptionEditor::plugin_scan_refresh)));
3350 #endif
3351
3352 #if (defined AUDIOUNIT_SUPPORT && defined MACVST_SUPPORT)
3353         bo = new BoolOption (
3354                         "",
3355                         _("Enable Mac VST support (requires restart or re-scan)"),
3356                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_use_macvst),
3357                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_use_macvst)
3358                         );
3359         add_option (_("Plugins/VST"), bo);
3360 #endif
3361
3362         bo = new BoolOption (
3363                         "discover-vst-on-start",
3364                         _("Scan for [new] VST Plugins on Application Start"),
3365                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_discover_vst_on_start),
3366                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_discover_vst_on_start)
3367                         );
3368         add_option (_("Plugins/VST"), bo);
3369         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3370                                             _("<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"));
3371
3372 #ifdef WINDOWS_VST_SUPPORT
3373         // currently verbose logging is only implemented for Windows VST.
3374         bo = new BoolOption (
3375                         "verbose-plugin-scan",
3376                         _("Verbose Plugin Scan"),
3377                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_verbose_plugin_scan),
3378                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_verbose_plugin_scan)
3379                         );
3380         add_option (_("Plugins/VST"), bo);
3381         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3382                                             _("<b>When enabled</b> additional information for every plugin is added to the Log Window."));
3383 #endif
3384
3385         add_option (_("Plugins/VST"), new VstTimeOutSliderOption (_rc_config));
3386
3387         add_option (_("Plugins/VST"),
3388                         new RcActionButton (_("Clear"),
3389                                 sigc::mem_fun (*this, &RCOptionEditor::clear_vst_cache),
3390                                 _("VST Cache:")));
3391
3392         add_option (_("Plugins/VST"),
3393                         new RcActionButton (_("Clear"),
3394                                 sigc::mem_fun (*this, &RCOptionEditor::clear_vst_blacklist),
3395                                 _("VST Blacklist:")));
3396 #endif
3397
3398 #ifdef LXVST_SUPPORT
3399         add_option (_("Plugins/VST"),
3400                         new RcActionButton (_("Edit"),
3401                                 sigc::mem_fun (*this, &RCOptionEditor::edit_lxvst_path),
3402                         _("Linux VST Path:")));
3403
3404         add_option (_("Plugins/VST"),
3405                         new RcConfigDisplay (
3406                                 "plugin-path-lxvst",
3407                                 _("Path:"),
3408                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugin_path_lxvst),
3409                                 0));
3410 #endif
3411
3412 #ifdef WINDOWS_VST_SUPPORT
3413         add_option (_("Plugins/VST"),
3414                         new RcActionButton (_("Edit"),
3415                                 sigc::mem_fun (*this, &RCOptionEditor::edit_vst_path),
3416                         _("Windows VST Path:")));
3417         add_option (_("Plugins/VST"),
3418                         new RcConfigDisplay (
3419                                 "plugin-path-vst",
3420                                 _("Path:"),
3421                                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugin_path_vst),
3422                                 ';'));
3423 #endif
3424
3425 #ifdef AUDIOUNIT_SUPPORT
3426
3427         add_option (_("Plugins/Audio Unit"), new OptionEditorHeading (_("Audio Unit")));
3428 #if 0
3429         add_option (_("Plugins/Audio Unit"),
3430                         new RcActionButton (_("Scan for Plugins"),
3431                                 sigc::mem_fun (*this, &RCOptionEditor::plugin_scan_refresh)));
3432 #endif
3433
3434         bo = new BoolOption (
3435                         "discover-audio-units",
3436                         _("Scan for [new] AudioUnit Plugins on Application Start"),
3437                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_discover_audio_units),
3438                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_discover_audio_units)
3439                         );
3440         add_option (_("Plugins/Audio Unit"), bo);
3441         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3442                                             _("<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."));
3443
3444         add_option (_("Plugins/Audio Unit"),
3445                         new RcActionButton (_("Clear"),
3446                                 sigc::mem_fun (*this, &RCOptionEditor::clear_au_cache),
3447                                 _("AU Cache:")));
3448
3449         add_option (_("Plugins/Audio Unit"),
3450                         new RcActionButton (_("Clear"),
3451                                 sigc::mem_fun (*this, &RCOptionEditor::clear_au_blacklist),
3452                                 _("AU Blacklist:")));
3453 #endif
3454
3455 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT || defined AUDIOUNIT_SUPPORT || defined HAVE_LV2)
3456         add_option (_("Plugins"), new OptionEditorHeading (_("Plugin GUI")));
3457         add_option (_("Plugins"),
3458              new BoolOption (
3459                      "open-gui-after-adding-plugin",
3460                      _("Automatically open the plugin GUI when adding a new plugin"),
3461                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_open_gui_after_adding_plugin),
3462                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_open_gui_after_adding_plugin)
3463                      ));
3464
3465 #if (defined LV2_SUPPORT && defined LV2_EXTENDED)
3466         add_option (_("Plugins"),
3467              new BoolOption (
3468                      "show-inline-display-by-default",
3469                      _("Show Plugin Inline Display on Mixerstrip by default"),
3470                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_inline_display_by_default),
3471                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_inline_display_by_default)
3472                      ));
3473
3474         _plugin_prefer_inline = new BoolOption (
3475                         "prefer-inline-over-gui",
3476                         _("Don't automatically open the plugin GUI when the plugin has an inline display mode"),
3477                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_prefer_inline_over_gui),
3478                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_prefer_inline_over_gui)
3479                         );
3480         add_option (_("Plugins"), _plugin_prefer_inline);
3481 #endif
3482
3483         add_option (_("Plugins"), new OptionEditorHeading (_("Instrument")));
3484
3485         bo = new BoolOption (
3486                         "ask-replace-instrument",
3487                         _("Ask to replace existing instrument plugin"),
3488                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_ask_replace_instrument),
3489                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_ask_replace_instrument)
3490                         );
3491         add_option (_("Plugins"), bo);
3492
3493         bo = new BoolOption (
3494                         "ask-setup_instrument",
3495                         _("Interactively configure instrument plugins on insert"),
3496                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_ask_setup_instrument),
3497                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_ask_setup_instrument)
3498                         );
3499         add_option (_("Plugins"), bo);
3500         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3501                         _("<b>When enabled</b> show a dialog to select instrument channel configuration before adding a multichannel plugin."));
3502
3503 #endif
3504         add_option (_("Plugins"), new OptionEditorBlank ());
3505
3506         /* INTERFACE */
3507 #if (defined OPTIONAL_CAIRO_IMAGE_SURFACE || defined CAIRO_SUPPORTS_FORCE_BUGGY_GRADIENTS_ENVIRONMENT_VARIABLE)
3508         add_option (_("Appearance"), new OptionEditorHeading (_("Graphics Acceleration")));
3509 #endif
3510
3511 #ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
3512         BoolOption* bgc = new BoolOption (
3513                 "cairo-image-surface",
3514                 _("Disable Graphics Hardware Acceleration (requires restart)"),
3515                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_cairo_image_surface),
3516                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_cairo_image_surface)
3517                 );
3518
3519         Gtkmm2ext::UI::instance()->set_tip (bgc->tip_widget(), string_compose (
3520                                 _("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));
3521         add_option (_("Appearance"), bgc);
3522 #endif
3523
3524 #ifdef CAIRO_SUPPORTS_FORCE_BUGGY_GRADIENTS_ENVIRONMENT_VARIABLE
3525         BoolOption* bgo = new BoolOption (
3526                 "buggy-gradients",
3527                 _("Possibly improve slow graphical performance (requires restart)"),
3528                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_buggy_gradients),
3529                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_buggy_gradients)
3530                 );
3531
3532         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));
3533         add_option (_("Appearance"), bgo);
3534 #endif
3535         add_option (_("Appearance"), new OptionEditorHeading (_("Graphical User Interface")));
3536
3537         add_option (_("Appearance"),
3538              new BoolOption (
3539                      "widget-prelight",
3540                      _("Highlight widgets on mouseover"),
3541                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_widget_prelight),
3542                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_widget_prelight)
3543                      ));
3544
3545         add_option (_("Appearance"),
3546              new BoolOption (
3547                      "use-tooltips",
3548                      _("Show tooltips if mouse hovers over a control"),
3549                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_tooltips),
3550                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_tooltips)
3551                      ));
3552
3553         bo = new BoolOption (
3554                         "super-rapid-clock-update",
3555                         _("Update clocks at TC Frame rate"),
3556                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_super_rapid_clock_update),
3557                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_super_rapid_clock_update)
3558                         );
3559         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget(),
3560                         _("<b>When enabled</b> clock displays are updated every Timecode Frame (fps).\n\n"
3561                                 "<b>When disabled</b> clock displays are updated only every 100ms."
3562                          ));
3563         add_option (_("Appearance"), bo);
3564
3565         add_option (_("Appearance"),
3566                         new BoolOption (
3567                                 "blink-rec-arm",
3568                                 _("Blink Rec-Arm buttons"),
3569                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_blink_rec_arm),
3570                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_blink_rec_arm)
3571                                 ));
3572
3573         add_option (_("Appearance"),
3574                         new BoolOption (
3575                                 "blink-alert-indicators",
3576                                 _("Blink Alert Indicators"),
3577                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_blink_alert_indicators),
3578                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_blink_alert_indicators)
3579                                 ));
3580
3581
3582 #ifndef __APPLE__
3583         /* font scaling does nothing with GDK/Quartz */
3584         add_option (_("Appearance"), new FontScalingOptions ());
3585 #endif
3586         add_option (_("Appearance/Editor"), new OptionEditorHeading (_("General")));
3587         add_option (_("Appearance/Editor"),
3588              new BoolOption (
3589                      "show-name-highlight",
3590                      _("Use name highlight bars in region displays (requires a restart)"),
3591                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_name_highlight),
3592                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_name_highlight)
3593                      ));
3594
3595         add_option (_("Appearance/Editor"),
3596                         new BoolOption (
3597                         "color-regions-using-track-color",
3598                         _("Region color follows track color"),
3599                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_color_regions_using_track_color),
3600                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_color_regions_using_track_color)
3601                         ));
3602
3603         add_option (_("Appearance/Editor"), new OptionEditorHeading (_("Waveforms")));
3604
3605         if (!Profile->get_mixbus()) {
3606                 add_option (_("Appearance/Editor"),
3607                                 new BoolOption (
3608                                         "show-waveforms",
3609                                         _("Show waveforms in regions"),
3610                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveforms),
3611                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveforms)
3612                                         ));
3613         }  // !mixbus
3614
3615         add_option (_("Appearance/Editor"),
3616              new BoolOption (
3617                      "show-waveforms-while-recording",
3618                      _("Show waveforms while recording"),
3619                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveforms_while_recording),
3620                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveforms_while_recording)
3621                      ));
3622
3623         add_option (_("Appearance/Editor"),
3624                         new BoolOption (
3625                         "show-waveform-clipping",
3626                         _("Show waveform clipping"),
3627                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveform_clipping),
3628                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveform_clipping)
3629                         ));
3630
3631         add_option (_("Appearance/Editor"), new ClipLevelOptions ());
3632
3633         ComboOption<WaveformScale>* wfs = new ComboOption<WaveformScale> (
3634                 "waveform-scale",
3635                 _("Waveform scale"),
3636                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_scale),
3637                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_scale)
3638                 );
3639
3640         wfs->add (Linear, _("linear"));
3641         wfs->add (Logarithmic, _("logarithmic"));
3642
3643         add_option (_("Appearance/Editor"), wfs);
3644
3645         ComboOption<WaveformShape>* wfsh = new ComboOption<WaveformShape> (
3646                 "waveform-shape",
3647                 _("Waveform shape"),
3648                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_shape),
3649                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_shape)
3650                 );
3651
3652         wfsh->add (Traditional, _("traditional"));
3653         wfsh->add (Rectified, _("rectified"));
3654
3655         add_option (_("Appearance/Editor"), wfsh);
3656
3657         add_option (_("Appearance/Editor"), new OptionEditorHeading (_("Editor Meters")));
3658
3659         add_option (_("Appearance/Editor"),
3660              new BoolOption (
3661                      "show-track-meters",
3662                      _("Show meters in track headers"),
3663                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_track_meters),
3664                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_track_meters)
3665                      ));
3666
3667         add_option (_("Appearance/Editor"),
3668              new BoolOption (
3669                      "editor-stereo-only-meters",
3670                      _("Limit track header meters to stereo"),
3671                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_editor_stereo_only_meters),
3672                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_editor_stereo_only_meters)
3673                      ));
3674
3675         add_option (_("Appearance/Editor"), new OptionEditorHeading (_("MIDI Regions")));
3676
3677         add_option (_("Appearance/Editor"),
3678                     new BoolOption (
3679                             "display-first-midi-bank-as-zero",
3680                             _("Display first MIDI bank/program as 0"),
3681                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_first_midi_bank_is_zero),
3682                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_first_midi_bank_is_zero)
3683                             ));
3684
3685         add_option (_("Appearance/Editor"),
3686              new BoolOption (
3687                      "never-display-periodic-midi",
3688                      _("Don't display periodic (MTC, MMC) SysEx messages in MIDI Regions"),
3689                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_never_display_periodic_midi),
3690                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_never_display_periodic_midi)
3691                      ));
3692
3693         add_option (_("Appearance/Editor"), new OptionEditorBlank ());
3694
3695         /* The names of these controls must be the same as those given in MixerStrip
3696            for the actual widgets being controlled.
3697         */
3698         _mixer_strip_visibility.add (0, X_("Input"), _("Input"));
3699         _mixer_strip_visibility.add (0, X_("PhaseInvert"), _("Phase Invert"));
3700         _mixer_strip_visibility.add (0, X_("RecMon"), _("Record & Monitor"));
3701         _mixer_strip_visibility.add (0, X_("SoloIsoLock"), _("Solo Iso / Lock"));
3702         _mixer_strip_visibility.add (0, X_("Output"), _("Output"));
3703         _mixer_strip_visibility.add (0, X_("Comments"), _("Comments"));
3704         _mixer_strip_visibility.add (0, X_("VCA"), _("VCA Assigns"));
3705
3706         add_option (_("Appearance/Mixer"),
3707                 new VisibilityOption (
3708                         _("Mixer Strip"),
3709                         &_mixer_strip_visibility,
3710                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_mixer_strip_visibility),
3711                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_mixer_strip_visibility)
3712                         )
3713                 );
3714
3715         add_option (_("Appearance/Mixer"),
3716              new BoolOption (
3717                      "default-narrow_ms",
3718                      _("Use narrow strips in the mixer for new strips by default"),
3719                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_default_narrow_ms),
3720                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_default_narrow_ms)
3721                      ));
3722
3723         add_option (_("Appearance/Mixer"), new OptionEditorBlank ());
3724
3725         add_option (_("Appearance/Toolbar"), new OptionEditorHeading (_("Main Transport Toolbar Items")));
3726
3727         add_option (_("Appearance/Toolbar"),
3728              new BoolOption (
3729                      "show-toolbar-recpunch",
3730                      _("Display Record/Punch Options"),
3731                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_toolbar_recpunch),
3732                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_toolbar_recpunch)
3733                      ));
3734
3735         add_option (_("Appearance/Toolbar"),
3736              new BoolOption (
3737                      "show-toolbar-monitoring",
3738                      _("Display Monitor Options"),
3739                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_toolbar_monitoring),
3740                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_toolbar_monitoring)
3741                      ));
3742
3743         add_option (_("Appearance/Toolbar"),
3744              new BoolOption (
3745                      "show-toolbar-selclock",
3746                      _("Display Selection Clock"),
3747                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_toolbar_selclock),
3748                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_toolbar_selclock)
3749                      ));
3750
3751         if (!ARDOUR::Profile->get_small_screen()) {
3752                 add_option (_("Appearance/Toolbar"),
3753                                 new BoolOption (
3754                                         "show-secondary-clock",
3755                                         _("Display Secondary Clock"),
3756                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_secondary_clock),
3757                                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_secondary_clock)
3758                                         ));
3759         }
3760
3761         add_option (_("Appearance/Toolbar"),
3762              new BoolOption (
3763                      "show-mini-timeline",
3764                      _("Display Navigation Timeline"),
3765                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_mini_timeline),
3766                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_mini_timeline)
3767                      ));
3768
3769         add_option (_("Appearance/Toolbar"),
3770              new BoolOption (
3771                      "show-editor-meter",
3772                      _("Display Master Level Meter"),
3773                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_editor_meter),
3774                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_editor_meter)
3775                      ));
3776
3777         add_option (_("Appearance/Toolbar"),
3778                         new ColumVisibilityOption (
3779                                 "action-table-columns", _("Lua Action Script Button Visibility"), 4,
3780                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_action_table_columns),
3781                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_action_table_columns)
3782                                 )
3783                         );
3784         add_option (_("Appearance/Toolbar"), new OptionEditorBlank ());
3785
3786
3787         /* and now the theme manager */
3788
3789         add_option (_("Appearance/Theme"), new OptionEditorHeading (_("Theme")));
3790
3791         add_option (_("Appearance/Theme"), new BoolOption (
3792                                 "flat-buttons",
3793                                 _("Draw \"flat\" buttons"),
3794                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_flat_buttons),
3795                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_flat_buttons)
3796                                 ));
3797
3798         add_option (_("Appearance/Theme"), new BoolOption (
3799                                 "meter-style-led",
3800                                 _("LED meter style"),
3801                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_style_led),
3802                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_style_led)
3803                                 ));
3804
3805
3806         HSliderOption *gui_hs = new HSliderOption(
3807                         "timeline-item-gradient-depth",
3808                         _("Waveforms color gradient depth"),
3809                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_gradient_depth),
3810                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_gradient_depth),
3811                         0, 1.0, 0.05
3812                         );
3813         gui_hs->scale().set_update_policy (Gtk::UPDATE_DELAYED);
3814         add_option (_("Appearance/Theme"), gui_hs);
3815
3816         gui_hs = new HSliderOption(
3817                         "timeline-item-gradient-depth",
3818                         _("Timeline item gradient depth"),
3819                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_timeline_item_gradient_depth),
3820                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_timeline_item_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         vector<string> icon_sets = ::get_icon_sets ();
3827         if (icon_sets.size() > 1) {
3828                 ComboOption<std::string>* io = new ComboOption<std::string> (
3829                                 "icon-set", _("Icon Set"),
3830                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_icon_set),
3831                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_icon_set)
3832                                 );
3833                 for (vector<string>::const_iterator i = icon_sets.begin (); i != icon_sets.end (); ++i) {
3834                         io->add (*i, *i);
3835                 }
3836                 add_option (_("Appearance/Theme"), io);
3837         }
3838
3839         add_option (_("Appearance/Colors"), new OptionEditorHeading (_("Colors")));
3840         add_option (_("Appearance/Colors"), new ColorThemeManager);
3841         add_option (_("Appearance/Colors"), new OptionEditorBlank ());
3842
3843         /* Quirks */
3844
3845         OptionEditorHeading* quirks_head = new OptionEditorHeading (_("Various Workarounds for Windowing Systems"));
3846
3847         quirks_head->set_note (string_compose (_("Rules for closing, minimizing, maximizing, and stay-on-top can vary\
3848 with each version of your OS, and the preferences that you've set in your OS.\n\n\
3849 You can adjust the options, below, to change how %1's windows and dialogs behave.\n\n\
3850 These settings will only take effect after %1 is restarted.\n\
3851         "), PROGRAM_NAME));
3852
3853         add_option (_("Appearance/Quirks"), quirks_head);
3854
3855         bo = new BoolOption (
3856                      "use-wm-visibility",
3857                      _("Use visibility information provided by your Window Manager/Desktop"),
3858                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_wm_visibility),
3859                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_wm_visibility)
3860                      );
3861         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget (),
3862                                 _("If you have trouble toggling between hidden Editor and Mixer windows, try changing this setting."));
3863         add_option (_("Appearance/Quirks"), bo);
3864
3865 #ifndef __APPLE__
3866         bo = new BoolOption (
3867                         "all-floating-windows-are-dialogs",
3868                         _("All floating windows are dialogs"),
3869                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_all_floating_windows_are_dialogs),
3870                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_all_floating_windows_are_dialogs)
3871                         );
3872         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget (),
3873                         _("Mark all floating windows to be type \"Dialog\" rather than using \"Utility\" for some.\nThis may help with some window managers."));
3874         add_option (_("Appearance/Quirks"), bo);
3875
3876         bo = new BoolOption (
3877                         "transients-follow-front",
3878                         _("Transient windows follow front window."),
3879                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_transients_follow_front),
3880                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_transients_follow_front)
3881                         );
3882         Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget (),
3883                                 _("Make transient windows follow the front window when toggling between the editor and mixer."));
3884         add_option (_("Appearance/Quirks"), bo);
3885 #endif
3886
3887         if (!Profile->get_mixbus()) {
3888                 bo = new BoolOption (
3889                                 "floating-monitor-section",
3890                                 _("Float detached monitor-section window"),
3891                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_floating_monitor_section),
3892                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_floating_monitor_section)
3893                                 );
3894                 Gtkmm2ext::UI::instance()->set_tip (bo->tip_widget (),
3895                                         _("When detaching the monitoring section, mark it as \"Utility\" window to stay in front."));
3896                 add_option (_("Appearance/Quirks"), bo);
3897         }
3898
3899         add_option (_("Appearance/Quirks"), new OptionEditorBlank ());
3900
3901         /* VIDEO Timeline */
3902         add_option (_("Video"), new OptionEditorHeading (_("Video Server")));
3903         add_option (_("Video"), new VideoTimelineOptions (_rc_config));
3904
3905         Widget::show_all ();
3906
3907         //trigger some parameter-changed messages which affect widget-visibility or -sensitivity
3908         parameter_changed ("send-ltc");
3909         parameter_changed ("sync-source");
3910         parameter_changed ("use-monitor-bus");
3911         parameter_changed ("open-gui-after-adding-plugin");
3912
3913         XMLNode* node = ARDOUR_UI::instance()->preferences_settings();
3914         if (node) {
3915                 /* gcc4 complains about ambiguity with Gtk::Widget::set_state
3916                    (Gtk::StateType) here !!!
3917                 */
3918                 Tabbable::set_state (*node, Stateful::loading_state_version);
3919         }
3920
3921         set_current_page (_("General"));
3922 }
3923
3924 void
3925 RCOptionEditor::parameter_changed (string const & p)
3926 {
3927         OptionEditor::parameter_changed (p);
3928
3929         if (p == "use-monitor-bus") {
3930                 bool const s = Config->get_use_monitor_bus ();
3931                 if (!s) {
3932                         /* we can't use this if we don't have a monitor bus */
3933                         Config->set_solo_control_is_listen_control (false);
3934                 }
3935                 _solo_control_is_listen_control->set_sensitive (s);
3936                 _listen_position->set_sensitive (s);
3937         } else if (p == "sync-source") {
3938                 _sync_source->set_sensitive (true);
3939                 if (_session) {
3940                         _sync_source->set_sensitive (!_session->config.get_external_sync());
3941                 }
3942                 switch(Config->get_sync_source()) {
3943                 case ARDOUR::MTC:
3944                 case ARDOUR::LTC:
3945                         _sync_genlock->set_sensitive (true);
3946                         _sync_framerate->set_sensitive (true);
3947                         _sync_source_2997->set_sensitive (true);
3948                         break;
3949                 default:
3950                         _sync_genlock->set_sensitive (false);
3951                         _sync_framerate->set_sensitive (false);
3952                         _sync_source_2997->set_sensitive (false);
3953                         break;
3954                 }
3955         } else if (p == "send-ltc") {
3956                 bool const s = Config->get_send_ltc ();
3957                 _ltc_send_continuously->set_sensitive (s);
3958                 _ltc_volume_slider->set_sensitive (s);
3959         } else if (p == "open-gui-after-adding-plugin" || p == "show-inline-display-by-default") {
3960 #if (defined LV2_SUPPORT && defined LV2_EXTENDED)
3961                 _plugin_prefer_inline->set_sensitive (UIConfiguration::instance().get_open_gui_after_adding_plugin() && UIConfiguration::instance().get_show_inline_display_by_default());
3962 #endif
3963         }
3964 }
3965
3966 void RCOptionEditor::plugin_scan_refresh () {
3967         PluginManager::instance().refresh();
3968 }
3969
3970 void RCOptionEditor::clear_vst_cache () {
3971         PluginManager::instance().clear_vst_cache();
3972 }
3973
3974 void RCOptionEditor::clear_vst_blacklist () {
3975         PluginManager::instance().clear_vst_blacklist();
3976 }
3977
3978 void RCOptionEditor::clear_au_cache () {
3979         PluginManager::instance().clear_au_cache();
3980 }
3981
3982 void RCOptionEditor::clear_au_blacklist () {
3983         PluginManager::instance().clear_au_blacklist();
3984 }
3985
3986 void RCOptionEditor::edit_lxvst_path () {
3987         Glib::RefPtr<Gdk::Window> win = get_parent_window ();
3988         Gtkmm2ext::PathsDialog *pd = new Gtkmm2ext::PathsDialog (
3989                 *current_toplevel(), _("Set Linux VST Search Path"),
3990                 _rc_config->get_plugin_path_lxvst(),
3991                 PluginManager::instance().get_default_lxvst_path()
3992                 );
3993         ResponseType r = (ResponseType) pd->run ();
3994         pd->hide();
3995         if (r == RESPONSE_ACCEPT) {
3996                 _rc_config->set_plugin_path_lxvst(pd->get_serialized_paths());
3997
3998                 MessageDialog msg (_("Re-scan Plugins now?"),
3999                                 false /*no markup*/, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, true /*modal*/);
4000                 msg.set_default_response (Gtk::RESPONSE_YES);
4001                 if (msg.run() == Gtk::RESPONSE_YES) {
4002                         msg.hide ();
4003                         plugin_scan_refresh ();
4004                 }
4005         }
4006         delete pd;
4007 }
4008
4009 void RCOptionEditor::edit_vst_path () {
4010         Gtkmm2ext::PathsDialog *pd = new Gtkmm2ext::PathsDialog (
4011                 *current_toplevel(), _("Set Windows VST Search Path"),
4012                 _rc_config->get_plugin_path_vst(),
4013                 PluginManager::instance().get_default_windows_vst_path()
4014                 );
4015         ResponseType r = (ResponseType) pd->run ();
4016         pd->hide();
4017         if (r == RESPONSE_ACCEPT) {
4018                 _rc_config->set_plugin_path_vst(pd->get_serialized_paths());
4019                 MessageDialog msg (_("Re-scan Plugins now?"),
4020                                 false /*no markup*/, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, true /*modal*/);
4021                 msg.set_default_response (Gtk::RESPONSE_YES);
4022                 if (msg.run() == Gtk::RESPONSE_YES) {
4023                         msg.hide ();
4024                         plugin_scan_refresh ();
4025                 }
4026         }
4027         delete pd;
4028 }
4029
4030
4031 void
4032 RCOptionEditor::populate_sync_options ()
4033 {
4034         vector<SyncSource> sync_opts = ARDOUR::get_available_sync_options ();
4035
4036         _sync_source->clear ();
4037
4038         for (vector<SyncSource>::iterator i = sync_opts.begin(); i != sync_opts.end(); ++i) {
4039                 _sync_source->add (*i, sync_source_to_string (*i));
4040         }
4041
4042         if (sync_opts.empty()) {
4043                 _sync_source->set_sensitive(false);
4044         } else {
4045                 if (std::find(sync_opts.begin(), sync_opts.end(), _rc_config->get_sync_source()) == sync_opts.end()) {
4046                         _rc_config->set_sync_source(sync_opts.front());
4047                 }
4048         }
4049
4050         parameter_changed ("sync-source");
4051 }
4052
4053 Gtk::Window*
4054 RCOptionEditor::use_own_window (bool and_fill_it)
4055 {
4056         bool new_window = !own_window ();
4057
4058         Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
4059
4060         if (win && new_window) {
4061                 win->set_name ("PreferencesWindow");
4062                 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Preferences"), this);
4063                 win->resize (1, 1);
4064                 win->set_resizable (false);
4065         }
4066
4067         return win;
4068 }
4069
4070 XMLNode&
4071 RCOptionEditor::get_state ()
4072 {
4073         XMLNode* node = new XMLNode (X_("Preferences"));
4074         node->add_child_nocopy (Tabbable::get_state());
4075         return *node;
4076 }