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