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