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