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