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