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