change wording of autosave option to be more clear
[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
41 #include "pbd/fpu.h"
42 #include "pbd/cpus.h"
43
44 #include "ardour/audioengine.h"
45 #include "ardour/dB.h"
46 #include "ardour/rc_configuration.h"
47 #include "ardour/control_protocol_manager.h"
48 #include "ardour/plugin_manager.h"
49 #include "control_protocol/control_protocol.h"
50
51 #include "canvas/wave_view.h"
52
53 #include "ardour_window.h"
54 #include "ardour_dialog.h"
55 #include "gui_thread.h"
56 #include "meter_patterns.h"
57 #include "midi_tracer.h"
58 #include "rc_option_editor.h"
59 #include "utils.h"
60 #include "midi_port_dialog.h"
61 #include "sfdb_ui.h"
62 #include "keyboard.h"
63 #include "theme_manager.h"
64 #include "ui_config.h"
65 #include "i18n.h"
66
67 using namespace std;
68 using namespace Gtk;
69 using namespace Gtkmm2ext;
70 using namespace PBD;
71 using namespace ARDOUR;
72 using namespace ARDOUR_UI_UTILS;
73
74 class ClickOptions : public OptionEditorBox
75 {
76 public:
77         ClickOptions (RCConfiguration* c, Gtk::Window* p)
78                 : _rc_config (c)
79                 , _click_browse_button (_("Browse..."))
80                 , _click_emphasis_browse_button (_("Browse..."))
81         {
82                 Table* t = manage (new Table (3, 3));
83                 t->set_spacings (4);
84
85                 Label* l = manage (left_aligned_label (_("Use default Click:")));
86                 t->attach (*l, 0, 1, 0, 1, FILL);
87                 t->attach (_use_default_click_check_button, 1, 2, 0, 1, FILL);
88                 _use_default_click_check_button.signal_toggled().connect (
89                     sigc::mem_fun (*this, &ClickOptions::use_default_click_toggled));
90
91                 l = manage (left_aligned_label (_("Click audio file:")));
92                 t->attach (*l, 0, 1, 1, 2, FILL);
93                 t->attach (_click_path_entry, 1, 2, 1, 2, FILL);
94                 _click_browse_button.signal_clicked ().connect (
95                     sigc::mem_fun (*this, &ClickOptions::click_browse_clicked));
96                 t->attach (_click_browse_button, 2, 3, 1, 2, FILL);
97
98                 l = manage (left_aligned_label (_("Click emphasis audio file:")));
99                 t->attach (*l, 0, 1, 2, 3, FILL);
100                 t->attach (_click_emphasis_path_entry, 1, 2, 2, 3, FILL);
101                 _click_emphasis_browse_button.signal_clicked ().connect (
102                     sigc::mem_fun (*this, &ClickOptions::click_emphasis_browse_clicked));
103                 t->attach (_click_emphasis_browse_button, 2, 3, 2, 3, FILL);
104                 
105                 _box->pack_start (*t, false, false);
106
107                 _click_path_entry.signal_activate().connect (sigc::mem_fun (*this, &ClickOptions::click_changed));      
108                 _click_emphasis_path_entry.signal_activate().connect (sigc::mem_fun (*this, &ClickOptions::click_emphasis_changed));
109
110                 if (_rc_config->get_click_sound ().empty() &&
111                     _rc_config->get_click_emphasis_sound().empty()) {
112                         _use_default_click_check_button.set_active (true);
113
114                 } else {
115                         _use_default_click_check_button.set_active (false);
116                 }
117         }
118
119         void parameter_changed (string const & p)
120         {
121                 if (p == "click-sound") {
122                         _click_path_entry.set_text (_rc_config->get_click_sound());
123                 } else if (p == "click-emphasis-sound") {
124                         _click_emphasis_path_entry.set_text (_rc_config->get_click_emphasis_sound());
125                 }
126         }
127
128         void set_state_from_config ()
129         {
130                 parameter_changed ("click-sound");
131                 parameter_changed ("click-emphasis-sound");
132         }
133
134 private:
135
136         void click_browse_clicked ()
137         {
138                 SoundFileChooser sfdb (_("Choose Click"));
139
140                 sfdb.show_all ();
141                 sfdb.present ();
142
143                 if (sfdb.run () == RESPONSE_OK) {
144                         click_chosen (sfdb.get_filename());
145                 }
146         }
147
148         void click_chosen (string const & path)
149         {
150                 _click_path_entry.set_text (path);
151                 _rc_config->set_click_sound (path);
152         }
153
154         void click_changed ()
155         {
156                 click_chosen (_click_path_entry.get_text ());
157         }
158         
159         void click_emphasis_browse_clicked ()
160         {
161                 SoundFileChooser sfdb (_("Choose Click Emphasis"));
162
163                 sfdb.show_all ();
164                 sfdb.present ();
165
166                 if (sfdb.run () == RESPONSE_OK) {
167                         click_emphasis_chosen (sfdb.get_filename());
168                 }
169         }
170
171         void click_emphasis_chosen (string const & path)
172         {
173                 _click_emphasis_path_entry.set_text (path);
174                 _rc_config->set_click_emphasis_sound (path);
175         }
176
177         void click_emphasis_changed ()
178         {
179                 click_emphasis_chosen (_click_emphasis_path_entry.get_text ());
180         }
181
182         void use_default_click_toggled ()
183         {
184                 if (_use_default_click_check_button.get_active ()) {
185                         _rc_config->set_click_sound ("");
186                         _rc_config->set_click_emphasis_sound ("");
187                         _click_path_entry.set_sensitive (false);
188                         _click_emphasis_path_entry.set_sensitive (false);
189                         _click_browse_button.set_sensitive (false);
190                         _click_emphasis_browse_button.set_sensitive (false);
191                 } else {
192                         _click_path_entry.set_sensitive (true);
193                         _click_emphasis_path_entry.set_sensitive (true);
194                         _click_browse_button.set_sensitive (true);
195                         _click_emphasis_browse_button.set_sensitive (true);
196                 }
197         }
198
199         RCConfiguration* _rc_config;
200         CheckButton _use_default_click_check_button;
201         Entry _click_path_entry;
202         Entry _click_emphasis_path_entry;
203         Button _click_browse_button;
204         Button _click_emphasis_browse_button;
205 };
206
207 class UndoOptions : public OptionEditorBox
208 {
209 public:
210         UndoOptions (RCConfiguration* c) :
211                 _rc_config (c),
212                 _limit_undo_button (_("Limit undo history to")),
213                 _save_undo_button (_("Save undo history of"))
214         {
215                 Table* t = new Table (2, 3);
216                 t->set_spacings (4);
217
218                 t->attach (_limit_undo_button, 0, 1, 0, 1, FILL);
219                 _limit_undo_spin.set_range (0, 512);
220                 _limit_undo_spin.set_increments (1, 10);
221                 t->attach (_limit_undo_spin, 1, 2, 0, 1, FILL | EXPAND);
222                 Label* l = manage (left_aligned_label (_("commands")));
223                 t->attach (*l, 2, 3, 0, 1);
224
225                 t->attach (_save_undo_button, 0, 1, 1, 2, FILL);
226                 _save_undo_spin.set_range (0, 512);
227                 _save_undo_spin.set_increments (1, 10);
228                 t->attach (_save_undo_spin, 1, 2, 1, 2, FILL | EXPAND);
229                 l = manage (left_aligned_label (_("commands")));
230                 t->attach (*l, 2, 3, 1, 2);
231
232                 _box->pack_start (*t);
233
234                 _limit_undo_button.signal_toggled().connect (sigc::mem_fun (*this, &UndoOptions::limit_undo_toggled));
235                 _limit_undo_spin.signal_value_changed().connect (sigc::mem_fun (*this, &UndoOptions::limit_undo_changed));
236                 _save_undo_button.signal_toggled().connect (sigc::mem_fun (*this, &UndoOptions::save_undo_toggled));
237                 _save_undo_spin.signal_value_changed().connect (sigc::mem_fun (*this, &UndoOptions::save_undo_changed));
238         }
239
240         void parameter_changed (string const & p)
241         {
242                 if (p == "history-depth") {
243                         int32_t const d = _rc_config->get_history_depth();
244                         _limit_undo_button.set_active (d != 0);
245                         _limit_undo_spin.set_sensitive (d != 0);
246                         _limit_undo_spin.set_value (d);
247                 } else if (p == "save-history") {
248                         bool const x = _rc_config->get_save_history ();
249                         _save_undo_button.set_active (x);
250                         _save_undo_spin.set_sensitive (x);
251                 } else if (p == "save-history-depth") {
252                         _save_undo_spin.set_value (_rc_config->get_saved_history_depth());
253                 }
254         }
255
256         void set_state_from_config ()
257         {
258                 parameter_changed ("save-history");
259                 parameter_changed ("history-depth");
260                 parameter_changed ("save-history-depth");
261         }
262
263         void limit_undo_toggled ()
264         {
265                 bool const x = _limit_undo_button.get_active ();
266                 _limit_undo_spin.set_sensitive (x);
267                 int32_t const n = x ? 16 : 0;
268                 _limit_undo_spin.set_value (n);
269                 _rc_config->set_history_depth (n);
270         }
271
272         void limit_undo_changed ()
273         {
274                 _rc_config->set_history_depth (_limit_undo_spin.get_value_as_int ());
275         }
276
277         void save_undo_toggled ()
278         {
279                 bool const x = _save_undo_button.get_active ();
280                 _rc_config->set_save_history (x);
281         }
282
283         void save_undo_changed ()
284         {
285                 _rc_config->set_saved_history_depth (_save_undo_spin.get_value_as_int ());
286         }
287
288 private:
289         RCConfiguration* _rc_config;
290         CheckButton _limit_undo_button;
291         SpinButton _limit_undo_spin;
292         CheckButton _save_undo_button;
293         SpinButton _save_undo_spin;
294 };
295
296
297
298 static const struct {
299     const char *name;
300     guint modifier;
301 } modifiers[] = {
302
303         { "Unmodified", 0 },
304
305 #ifdef GTKOSX
306
307         /* Command = Meta
308            Option/Alt = Mod1
309         */
310         { "Key|Shift", GDK_SHIFT_MASK },
311         { "Command", GDK_META_MASK },
312         { "Control", GDK_CONTROL_MASK },
313         { "Option", GDK_MOD1_MASK },
314         { "Command-Shift", GDK_META_MASK|GDK_SHIFT_MASK },
315         { "Command-Option", GDK_MOD1_MASK|GDK_META_MASK },
316         { "Option-Shift", GDK_MOD1_MASK|GDK_SHIFT_MASK },
317         { "Control-Shift", GDK_CONTROL_MASK|GDK_SHIFT_MASK },
318         { "Shift-Command-Option", GDK_MOD5_MASK|GDK_SHIFT_MASK|GDK_META_MASK },
319
320 #else
321         { "Key|Shift", GDK_SHIFT_MASK },
322         { "Control", GDK_CONTROL_MASK },
323         { "Alt", GDK_MOD1_MASK },
324         { "Control-Shift", GDK_CONTROL_MASK|GDK_SHIFT_MASK },
325         { "Control-Alt", GDK_CONTROL_MASK|GDK_MOD1_MASK },
326         { "Shift-Alt", GDK_SHIFT_MASK|GDK_MOD1_MASK },
327         { "Control-Shift-Alt", GDK_CONTROL_MASK|GDK_SHIFT_MASK|GDK_MOD1_MASK },
328         { "Alt-Windows", GDK_MOD1_MASK|GDK_MOD4_MASK },
329         { "Mod2", GDK_MOD2_MASK },
330         { "Mod3", GDK_MOD3_MASK },
331         { "Windows", GDK_MOD4_MASK },
332         { "Mod5", GDK_MOD5_MASK },
333 #endif
334         { 0, 0 }
335 };
336
337
338 class KeyboardOptions : public OptionEditorBox
339 {
340 public:
341         KeyboardOptions () :
342                   _delete_button_adjustment (3, 1, 12),
343                   _delete_button_spin (_delete_button_adjustment),
344                   _edit_button_adjustment (3, 1, 5),
345                   _edit_button_spin (_edit_button_adjustment),
346                   _insert_note_button_adjustment (3, 1, 5),
347                   _insert_note_button_spin (_insert_note_button_adjustment)
348         {
349                 /* internationalize and prepare for use with combos */
350
351                 vector<string> dumb;
352                 for (int i = 0; modifiers[i].name; ++i) {
353                         dumb.push_back (S_(modifiers[i].name));
354                 }
355
356                 set_popdown_strings (_edit_modifier_combo, dumb);
357                 _edit_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::edit_modifier_chosen));
358
359                 for (int x = 0; modifiers[x].name; ++x) {
360                         if (modifiers[x].modifier == Keyboard::edit_modifier ()) {
361                                 _edit_modifier_combo.set_active_text (S_(modifiers[x].name));
362                                 break;
363                         }
364                 }
365
366                 Table* t = manage (new Table (5, 11));
367                 t->set_spacings (4);
368
369                 int row = 0;
370                 int col = 0;
371
372                 Label* l = manage (left_aligned_label (_("Select Keyboard layout:")));
373                 l->set_name ("OptionsLabel");
374
375                 vector<string> strs;
376
377                 for (map<string,string>::iterator bf = Keyboard::binding_files.begin(); bf != Keyboard::binding_files.end(); ++bf) {
378                         strs.push_back (bf->first);
379                 }
380
381                 set_popdown_strings (_keyboard_layout_selector, strs);
382                 _keyboard_layout_selector.set_active_text (Keyboard::current_binding_name());
383                 _keyboard_layout_selector.signal_changed().connect (sigc::mem_fun (*this, &KeyboardOptions::bindings_changed));
384
385                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
386                 t->attach (_keyboard_layout_selector, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
387
388                 ++row;
389                 col = 0;
390
391                 l = manage (left_aligned_label (_("When Clicking:")));
392                 l->set_name ("OptionEditorHeading");
393                 t->attach (*l, col, col + 2, row, row + 1, FILL | EXPAND, FILL);
394
395                 ++row;
396                 col = 1;
397
398                 l = manage (left_aligned_label (_("Edit using:")));
399                 l->set_name ("OptionsLabel");
400
401                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
402                 t->attach (_edit_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
403
404                 l = manage (new Label (_("+ button")));
405                 l->set_name ("OptionsLabel");
406
407                 t->attach (*l, col + 3, col + 4, row, row + 1, FILL | EXPAND, FILL);
408                 t->attach (_edit_button_spin, col + 4, col + 5, row, row + 1, FILL | EXPAND, FILL);
409
410                 _edit_button_spin.set_name ("OptionsEntry");
411                 _edit_button_adjustment.set_value (Keyboard::edit_button());
412                 _edit_button_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::edit_button_changed));
413
414                 ++row;
415                 col = 1;
416
417                 set_popdown_strings (_delete_modifier_combo, dumb);
418                 _delete_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::delete_modifier_chosen));
419
420                 for (int x = 0; modifiers[x].name; ++x) {
421                         if (modifiers[x].modifier == Keyboard::delete_modifier ()) {
422                                 _delete_modifier_combo.set_active_text (S_(modifiers[x].name));
423                                 break;
424                         }
425                 }
426
427                 l = manage (left_aligned_label (_("Delete using:")));
428                 l->set_name ("OptionsLabel");
429
430                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
431                 t->attach (_delete_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
432
433                 l = manage (new Label (_("+ button")));
434                 l->set_name ("OptionsLabel");
435
436                 t->attach (*l, col + 3, col + 4, row, row + 1, FILL | EXPAND, FILL);
437                 t->attach (_delete_button_spin, col + 4, col + 5, row, row + 1, FILL | EXPAND, FILL);
438
439                 _delete_button_spin.set_name ("OptionsEntry");
440                 _delete_button_adjustment.set_value (Keyboard::delete_button());
441                 _delete_button_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::delete_button_changed));
442
443                 ++row;
444                 col = 1;
445
446                 set_popdown_strings (_insert_note_modifier_combo, dumb);
447                 _insert_note_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::insert_note_modifier_chosen));
448
449                 for (int x = 0; modifiers[x].name; ++x) {
450                         if (modifiers[x].modifier == Keyboard::insert_note_modifier ()) {
451                                 _insert_note_modifier_combo.set_active_text (S_(modifiers[x].name));
452                                 break;
453                         }
454                 }
455
456                 l = manage (left_aligned_label (_("Insert note using:")));
457                 l->set_name ("OptionsLabel");
458
459                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
460                 t->attach (_insert_note_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
461
462                 l = manage (new Label (_("+ button")));
463                 l->set_name ("OptionsLabel");
464
465                 t->attach (*l, col + 3, col + 4, row, row + 1, FILL | EXPAND, FILL);
466                 t->attach (_insert_note_button_spin, col + 4, col + 5, row, row + 1, FILL | EXPAND, FILL);
467
468                 _insert_note_button_spin.set_name ("OptionsEntry");
469                 _insert_note_button_adjustment.set_value (Keyboard::insert_note_button());
470                 _insert_note_button_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::insert_note_button_changed));
471
472                 ++row;
473
474                 l = manage (left_aligned_label (_("When Beginning a Drag:")));
475                 l->set_name ("OptionEditorHeading");
476                 t->attach (*l, 0, 2, row, row + 1, FILL | EXPAND, FILL);
477
478                 ++row;
479                 col = 1;
480
481                 /* copy modifier */
482                 set_popdown_strings (_copy_modifier_combo, dumb);
483                 _copy_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::copy_modifier_chosen));
484
485                 for (int x = 0; modifiers[x].name; ++x) {
486                         if (modifiers[x].modifier == (guint) Keyboard::CopyModifier) {
487                                 _copy_modifier_combo.set_active_text (S_(modifiers[x].name));
488                                 break;
489                         }
490                 }
491
492                 l = manage (left_aligned_label (_("Copy items using:")));
493                 l->set_name ("OptionsLabel");
494
495                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
496                 t->attach (_copy_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
497
498                                 ++row;
499                 col = 1;
500
501                 /* constraint modifier */
502                 set_popdown_strings (_constraint_modifier_combo, dumb);
503                 _constraint_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::constraint_modifier_chosen));
504
505                 for (int x = 0; modifiers[x].name; ++x) {
506                         if (modifiers[x].modifier == (guint) ArdourKeyboard::constraint_modifier ()) {
507                                 _constraint_modifier_combo.set_active_text (S_(modifiers[x].name));
508                                 break;
509                         }
510                 }
511
512                 l = manage (left_aligned_label (_("Constrain drag using:")));
513                 l->set_name ("OptionsLabel");
514
515                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
516                 t->attach (_constraint_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
517
518                 ++row;
519
520                 l = manage (left_aligned_label (_("When Beginning a Trim:")));
521                 l->set_name ("OptionEditorHeading");
522                 t->attach (*l, 0, 2, row, row + 1, FILL | EXPAND, FILL);
523
524                 ++row;
525                 col = 1;
526
527                 /* trim_contents */
528                 set_popdown_strings (_trim_contents_combo, dumb);
529                 _trim_contents_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::trim_contents_modifier_chosen));
530
531                 for (int x = 0; modifiers[x].name; ++x) {
532                         if (modifiers[x].modifier == (guint) ArdourKeyboard::trim_contents_modifier ()) {
533                                 _trim_contents_combo.set_active_text (S_(modifiers[x].name));
534                                 break;
535                         }
536                 }
537
538                 l = manage (left_aligned_label (_("Trim contents using:")));
539                 l->set_name ("OptionsLabel");
540
541                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
542                 t->attach (_trim_contents_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
543
544                 ++row;
545                 col = 1;
546
547                 /* anchored trim */
548                 set_popdown_strings (_trim_anchored_combo, dumb);
549                 _trim_anchored_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::trim_anchored_modifier_chosen));
550
551                 for (int x = 0; modifiers[x].name; ++x) {
552                         if (modifiers[x].modifier == (guint) ArdourKeyboard::trim_anchored_modifier ()) {
553                                 _trim_anchored_combo.set_active_text (S_(modifiers[x].name));
554                                 break;
555                         }
556                 }
557
558                 l = manage (left_aligned_label (_("Anchored trim using:")));
559                 l->set_name ("OptionsLabel");
560
561                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
562                 ++col;
563                 t->attach (_trim_anchored_combo, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
564
565                 ++row;
566                 col = 1;
567
568                 /* jump trim disabled for now
569                 set_popdown_strings (_trim_jump_combo, dumb);
570                 _trim_jump_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::trim_jump_modifier_chosen));
571
572                 for (int x = 0; modifiers[x].name; ++x) {
573                         if (modifiers[x].modifier == (guint) Keyboard::trim_jump_modifier ()) {
574                                 _trim_jump_combo.set_active_text (S_(modifiers[x].name));
575                                 break;
576                         }
577                 }
578
579                 l = manage (left_aligned_label (_("Jump after trim using:")));
580                 l->set_name ("OptionsLabel");
581
582                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
583                 ++col;
584                 t->attach (_trim_jump_combo, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
585
586                 ++row;
587                 col = 1;
588                 */
589
590                 /* note resize relative */
591                 set_popdown_strings (_note_size_relative_combo, dumb);
592                 _note_size_relative_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::note_size_relative_modifier_chosen));
593
594                 for (int x = 0; modifiers[x].name; ++x) {
595                         if (modifiers[x].modifier == (guint) ArdourKeyboard::note_size_relative_modifier ()) {
596                                 _note_size_relative_combo.set_active_text (S_(modifiers[x].name));
597                                 break;
598                         }
599                 }
600
601                 l = manage (left_aligned_label (_("Resize notes relatively using:")));
602                 l->set_name ("OptionsLabel");
603
604                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
605                 ++col;
606                 t->attach (_note_size_relative_combo, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
607
608                 ++row;
609
610                 l = manage (left_aligned_label (_("While Dragging:")));
611                 l->set_name ("OptionEditorHeading");
612                 t->attach (*l, 0, 2, row, row + 1, FILL | EXPAND, FILL);
613
614                 ++row;
615                 col = 1;
616
617                 /* ignore snap */
618                 set_popdown_strings (_snap_modifier_combo, dumb);
619                 _snap_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::snap_modifier_chosen));
620
621                 for (int x = 0; modifiers[x].name; ++x) {
622                         if (modifiers[x].modifier == (guint) Keyboard::snap_modifier ()) {
623                                 _snap_modifier_combo.set_active_text (S_(modifiers[x].name));
624                                 break;
625                         }
626                 }
627
628                 l = manage (left_aligned_label (_("Ignore snap using:")));
629                 l->set_name ("OptionsLabel");
630
631                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
632                 t->attach (_snap_modifier_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
633
634                 ++row;
635                 col = 1;
636
637                 /* snap delta */
638                 set_popdown_strings (_snap_delta_combo, dumb);
639                 _snap_delta_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::snap_delta_modifier_chosen));
640
641                 for (int x = 0; modifiers[x].name; ++x) {
642                         if (modifiers[x].modifier == (guint) Keyboard::snap_delta_modifier ()) {
643                                 _snap_delta_combo.set_active_text (S_(modifiers[x].name));
644                                 break;
645                         }
646                 }
647
648                 l = manage (left_aligned_label (_("Snap relatively using:")));
649                 l->set_name ("OptionsLabel");
650
651                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
652                 t->attach (_snap_delta_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
653
654                 ++row;
655
656                 l = manage (left_aligned_label (_("While Trimming:")));
657                 l->set_name ("OptionEditorHeading");
658                 t->attach (*l, 0, 2, row, row + 1, FILL | EXPAND, FILL);
659
660                 ++row;
661                 col = 1;
662
663                 /* trim_overlap */
664                 set_popdown_strings (_trim_overlap_combo, dumb);
665                 _trim_overlap_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::trim_overlap_modifier_chosen));
666
667                 for (int x = 0; modifiers[x].name; ++x) {
668                         if (modifiers[x].modifier == (guint) ArdourKeyboard::trim_overlap_modifier ()) {
669                                 _trim_overlap_combo.set_active_text (S_(modifiers[x].name));
670                                 break;
671                         }
672                 }
673
674                 l = manage (left_aligned_label (_("Resize overlapped regions using:")));
675                 l->set_name ("OptionsLabel");
676
677                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
678                 t->attach (_trim_overlap_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
679
680                 ++row;
681
682                 l = manage (left_aligned_label (_("While Dragging Control Points:")));
683                 l->set_name ("OptionEditorHeading");
684                 t->attach (*l, 0, 2, row, row + 1, FILL | EXPAND, FILL);
685
686                 ++row;
687                 col = 1;
688
689                 /* fine adjust */
690                 set_popdown_strings (_fine_adjust_combo, dumb);
691                 _fine_adjust_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::fine_adjust_modifier_chosen));
692
693                 for (int x = 0; modifiers[x].name; ++x) {
694                         if (modifiers[x].modifier == (guint) ArdourKeyboard::fine_adjust_modifier ()) {
695                                 _fine_adjust_combo.set_active_text (S_(modifiers[x].name));
696                                 break;
697                         }
698                 }
699
700                 l = manage (left_aligned_label (_("Fine adjust using:")));
701                 l->set_name ("OptionsLabel");
702
703                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
704                 t->attach (_fine_adjust_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
705
706                 ++row;
707                 col = 1;
708
709                 /* push points */
710                 set_popdown_strings (_push_points_combo, dumb);
711                 _push_points_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::push_points_modifier_chosen));
712
713                 for (int x = 0; modifiers[x].name; ++x) {
714                         if (modifiers[x].modifier == (guint) ArdourKeyboard::push_points_modifier ()) {
715                                 _push_points_combo.set_active_text (S_(modifiers[x].name));
716                                 break;
717                         }
718                 }
719
720                 l = manage (left_aligned_label (_("Push points using:")));
721                 l->set_name ("OptionsLabel");
722
723                 t->attach (*l, col, col + 1, row, row + 1, FILL | EXPAND, FILL);
724                 t->attach (_push_points_combo, col + 1, col + 2, row, row + 1, FILL | EXPAND, FILL);
725
726                 _box->pack_start (*t, false, false);
727         }
728
729         void parameter_changed (string const &)
730         {
731                 /* XXX: these aren't really config options... */
732         }
733
734         void set_state_from_config ()
735         {
736                 /* XXX: these aren't really config options... */
737         }
738
739 private:
740
741         void bindings_changed ()
742         {
743                 string const txt = _keyboard_layout_selector.get_active_text();
744
745                 /* XXX: config...?  for all this keyboard stuff */
746
747                 for (map<string,string>::iterator i = Keyboard::binding_files.begin(); i != Keyboard::binding_files.end(); ++i) {
748                         if (txt == i->first) {
749                                 if (Keyboard::load_keybindings (i->second)) {
750                                         Keyboard::save_keybindings ();
751                                 }
752                         }
753                 }
754         }
755
756         void edit_modifier_chosen ()
757         {
758                 string const txt = _edit_modifier_combo.get_active_text();
759
760                 for (int i = 0; modifiers[i].name; ++i) {
761                         if (txt == _(modifiers[i].name)) {
762                                 Keyboard::set_edit_modifier (modifiers[i].modifier);
763                                 break;
764                         }
765                 }
766         }
767
768         void delete_modifier_chosen ()
769         {
770                 string const txt = _delete_modifier_combo.get_active_text();
771
772                 for (int i = 0; modifiers[i].name; ++i) {
773                         if (txt == _(modifiers[i].name)) {
774                                 Keyboard::set_delete_modifier (modifiers[i].modifier);
775                                 break;
776                         }
777                 }
778         }
779
780         void copy_modifier_chosen ()
781         {
782                 string const txt = _copy_modifier_combo.get_active_text();
783
784                 for (int i = 0; modifiers[i].name; ++i) {
785                         if (txt == _(modifiers[i].name)) {
786                                 Keyboard::set_copy_modifier (modifiers[i].modifier);
787                                 break;
788                         }
789                 }
790         }
791
792         void insert_note_modifier_chosen ()
793         {
794                 string const txt = _insert_note_modifier_combo.get_active_text();
795
796                 for (int i = 0; modifiers[i].name; ++i) {
797                         if (txt == _(modifiers[i].name)) {
798                                 Keyboard::set_insert_note_modifier (modifiers[i].modifier);
799                                 break;
800                         }
801                 }
802         }
803
804         void snap_modifier_chosen ()
805         {
806                 string const txt = _snap_modifier_combo.get_active_text();
807
808                 for (int i = 0; modifiers[i].name; ++i) {
809                         if (txt == _(modifiers[i].name)) {
810                                 Keyboard::set_snap_modifier (modifiers[i].modifier);
811                                 break;
812                         }
813                 }
814         }
815
816         void snap_delta_modifier_chosen ()
817         {
818                 string const txt = _snap_delta_combo.get_active_text();
819
820                 for (int i = 0; modifiers[i].name; ++i) {
821                         if (txt == _(modifiers[i].name)) {
822                                 Keyboard::set_snap_delta_modifier (modifiers[i].modifier);
823                                 break;
824                         }
825                 }
826         }
827
828         void constraint_modifier_chosen ()
829         {
830                 string const txt = _constraint_modifier_combo.get_active_text();
831
832                 for (int i = 0; modifiers[i].name; ++i) {
833                         if (txt == _(modifiers[i].name)) {
834                                 ArdourKeyboard::set_constraint_modifier (modifiers[i].modifier);
835                                 break;
836                         }
837                 }
838         }
839
840         void trim_contents_modifier_chosen ()
841         {
842                 string const txt = _trim_contents_combo.get_active_text();
843
844                 for (int i = 0; modifiers[i].name; ++i) {
845                         if (txt == _(modifiers[i].name)) {
846                                 ArdourKeyboard::set_trim_contents_modifier (modifiers[i].modifier);
847                                 break;
848                         }
849                 }
850         }
851
852         void trim_overlap_modifier_chosen ()
853         {
854                 string const txt = _trim_overlap_combo.get_active_text();
855
856                 for (int i = 0; modifiers[i].name; ++i) {
857                         if (txt == _(modifiers[i].name)) {
858                                 ArdourKeyboard::set_trim_overlap_modifier (modifiers[i].modifier);
859                                 break;
860                         }
861                 }
862         }
863
864         void trim_anchored_modifier_chosen ()
865         {
866                 string const txt = _trim_anchored_combo.get_active_text();
867
868                 for (int i = 0; modifiers[i].name; ++i) {
869                         if (txt == _(modifiers[i].name)) {
870                                 ArdourKeyboard::set_trim_anchored_modifier (modifiers[i].modifier);
871                                 break;
872                         }
873                 }
874         }
875
876         void fine_adjust_modifier_chosen ()
877         {
878                 string const txt = _fine_adjust_combo.get_active_text();
879
880                 for (int i = 0; modifiers[i].name; ++i) {
881                         if (txt == _(modifiers[i].name)) {
882                                 ArdourKeyboard::set_fine_adjust_modifier (modifiers[i].modifier);
883                                 break;
884                         }
885                 }
886         }
887
888         void push_points_modifier_chosen ()
889         {
890                 string const txt = _push_points_combo.get_active_text();
891
892                 for (int i = 0; modifiers[i].name; ++i) {
893                         if (txt == _(modifiers[i].name)) {
894                                 ArdourKeyboard::set_push_points_modifier (modifiers[i].modifier);
895                                 break;
896                         }
897                 }
898         }
899
900         void note_size_relative_modifier_chosen ()
901         {
902                 string const txt = _note_size_relative_combo.get_active_text();
903
904                 for (int i = 0; modifiers[i].name; ++i) {
905                         if (txt == _(modifiers[i].name)) {
906                                 ArdourKeyboard::set_note_size_relative_modifier (modifiers[i].modifier);
907                                 break;
908                         }
909                 }
910         }
911
912         void delete_button_changed ()
913         {
914                 Keyboard::set_delete_button (_delete_button_spin.get_value_as_int());
915         }
916
917         void edit_button_changed ()
918         {
919                 Keyboard::set_edit_button (_edit_button_spin.get_value_as_int());
920         }
921
922         void insert_note_button_changed ()
923         {
924                 Keyboard::set_insert_note_button (_insert_note_button_spin.get_value_as_int());
925         }
926
927         ComboBoxText _keyboard_layout_selector;
928         ComboBoxText _edit_modifier_combo;
929         ComboBoxText _delete_modifier_combo;
930         ComboBoxText _copy_modifier_combo;
931         ComboBoxText _insert_note_modifier_combo;
932         ComboBoxText _snap_modifier_combo;
933         ComboBoxText _snap_delta_combo;
934         ComboBoxText _constraint_modifier_combo;
935         ComboBoxText _trim_contents_combo;
936         ComboBoxText _trim_overlap_combo;
937         ComboBoxText _trim_anchored_combo;
938         ComboBoxText _trim_jump_combo;
939         ComboBoxText _fine_adjust_combo;
940         ComboBoxText _push_points_combo;
941         ComboBoxText _note_size_relative_combo;
942         Adjustment _delete_button_adjustment;
943         SpinButton _delete_button_spin;
944         Adjustment _edit_button_adjustment;
945         SpinButton _edit_button_spin;
946         Adjustment _insert_note_button_adjustment;
947         SpinButton _insert_note_button_spin;
948
949 };
950
951 class FontScalingOptions : public OptionEditorBox
952 {
953 public:
954         FontScalingOptions () :
955                 _dpi_adjustment (100, 50, 250, 1, 5),
956                 _dpi_slider (_dpi_adjustment)
957         {
958                 _dpi_adjustment.set_value (UIConfiguration::instance().get_font_scale() / 1024.);
959
960                 Label* l = manage (new Label (_("GUI and Font scaling:")));
961                 l->set_name ("OptionsLabel");
962
963                  const Glib::ustring dflt = _("Default");
964                  const Glib::ustring empty = X_(""); // despite gtk-doc saying so, NULL does not work as reference
965
966                 _dpi_slider.set_name("FontScaleSlider");
967                 _dpi_slider.set_update_policy (UPDATE_DISCONTINUOUS);
968                 _dpi_slider.set_draw_value(false);
969                 _dpi_slider.add_mark(50,  Gtk::POS_TOP, empty);
970                 _dpi_slider.add_mark(60,  Gtk::POS_TOP, empty);
971                 _dpi_slider.add_mark(70,  Gtk::POS_TOP, empty);
972                 _dpi_slider.add_mark(80,  Gtk::POS_TOP, empty);
973                 _dpi_slider.add_mark(90,  Gtk::POS_TOP, empty);
974                 _dpi_slider.add_mark(100, Gtk::POS_TOP, dflt);
975                 _dpi_slider.add_mark(125, Gtk::POS_TOP, empty);
976                 _dpi_slider.add_mark(150, Gtk::POS_TOP, empty);
977                 _dpi_slider.add_mark(175, Gtk::POS_TOP, empty);
978                 _dpi_slider.add_mark(200, Gtk::POS_TOP, empty);
979                 _dpi_slider.add_mark(225, Gtk::POS_TOP, empty);
980                 _dpi_slider.add_mark(250, Gtk::POS_TOP, empty);
981
982                 HBox* h = manage (new HBox);
983                 h->set_spacing (4);
984                 h->pack_start (*l, false, false);
985                 h->pack_start (_dpi_slider, true, true);
986
987                 _box->pack_start (*h, false, false);
988
989                 set_note (_("Adjusting the scale require an application restart to re-layout."));
990
991                 _dpi_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &FontScalingOptions::dpi_changed));
992         }
993
994         void parameter_changed (string const & p)
995         {
996                 if (p == "font-scale") {
997                         _dpi_adjustment.set_value (UIConfiguration::instance().get_font_scale() / 1024.);
998                 }
999         }
1000
1001         void set_state_from_config ()
1002         {
1003                 parameter_changed ("font-scale");
1004         }
1005
1006 private:
1007
1008         void dpi_changed ()
1009         {
1010                 UIConfiguration::instance().set_font_scale ((long) floor (_dpi_adjustment.get_value() * 1024.));
1011                 /* XXX: should be triggered from the parameter changed signal */
1012                 UIConfiguration::instance().reset_dpi ();
1013         }
1014
1015         Adjustment _dpi_adjustment;
1016         HScale _dpi_slider;
1017 };
1018
1019 class ClipLevelOptions : public OptionEditorBox
1020 {
1021 public:
1022         ClipLevelOptions () 
1023                 : _clip_level_adjustment (-.5, -50.0, 0.0, 0.1, 1.0) /* units of dB */
1024                 , _clip_level_slider (_clip_level_adjustment)
1025         {
1026                 _clip_level_adjustment.set_value (UIConfiguration::instance().get_waveform_clip_level ());
1027
1028                 Label* l = manage (new Label (_("Waveform Clip Level (dBFS):")));
1029                 l->set_name ("OptionsLabel");
1030
1031                 _clip_level_slider.set_update_policy (UPDATE_DISCONTINUOUS);
1032                 HBox* h = manage (new HBox);
1033                 h->set_spacing (4);
1034                 h->pack_start (*l, false, false);
1035                 h->pack_start (_clip_level_slider, true, true);
1036
1037                 _box->pack_start (*h, false, false);
1038
1039                 _clip_level_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &ClipLevelOptions::clip_level_changed));
1040         }
1041
1042         void parameter_changed (string const & p)
1043         {
1044                 if (p == "waveform-clip-level") {
1045                         _clip_level_adjustment.set_value (UIConfiguration::instance().get_waveform_clip_level());
1046                 }
1047         }
1048
1049         void set_state_from_config ()
1050         {
1051                 parameter_changed ("waveform-clip-level");
1052         }
1053
1054 private:
1055
1056         void clip_level_changed ()
1057         {
1058                 UIConfiguration::instance().set_waveform_clip_level (_clip_level_adjustment.get_value());
1059                 /* XXX: should be triggered from the parameter changed signal */
1060                 ArdourCanvas::WaveView::set_clip_level (_clip_level_adjustment.get_value());
1061         }
1062
1063         Adjustment _clip_level_adjustment;
1064         HScale _clip_level_slider;
1065 };
1066
1067 class BufferingOptions : public OptionEditorBox
1068 {
1069 public:
1070         BufferingOptions (RCConfiguration* c)
1071                 : _rc_config (c)
1072                 , _playback_adjustment (5, 1, 60, 1, 4)
1073                 , _capture_adjustment (5, 1, 60, 1, 4)
1074                 , _playback_slider (_playback_adjustment)
1075                 , _capture_slider (_capture_adjustment)
1076         {
1077                 vector<string> presets;
1078
1079                 /* these must match the order of the enums for BufferingPreset */
1080                 
1081                 presets.push_back (_("Small sessions (4-16 tracks)"));
1082                 presets.push_back (_("Medium sessions (16-64 tracks)"));
1083                 presets.push_back (_("Large sessions (64+ tracks)"));
1084                 presets.push_back (_("Custom (set by sliders below)"));
1085
1086                 set_popdown_strings (_buffering_presets_combo, presets);
1087
1088                 Label* l = manage (new Label (_("Preset:")));
1089                 l->set_name ("OptionsLabel");
1090                 HBox* h = manage (new HBox);
1091                 h->set_spacing (12);
1092                 h->pack_start (*l, false, false);
1093                 h->pack_start (_buffering_presets_combo, true, true);
1094                 _box->pack_start (*h, false, false);
1095
1096                 _buffering_presets_combo.signal_changed().connect (sigc::mem_fun (*this, &BufferingOptions::preset_changed));
1097                 
1098                 _playback_adjustment.set_value (_rc_config->get_audio_playback_buffer_seconds());
1099
1100                 l = manage (new Label (_("Playback (seconds of buffering):")));
1101                 l->set_name ("OptionsLabel");
1102
1103                 _playback_slider.set_update_policy (UPDATE_DISCONTINUOUS);
1104                 h = manage (new HBox);
1105                 h->set_spacing (4);
1106                 h->pack_start (*l, false, false);
1107                 h->pack_start (_playback_slider, true, true);
1108
1109                 _box->pack_start (*h, false, false);
1110
1111                 _capture_adjustment.set_value (_rc_config->get_audio_capture_buffer_seconds());
1112
1113                 l = manage (new Label (_("Recording (seconds of buffering):")));
1114                 l->set_name ("OptionsLabel");
1115
1116                 _capture_slider.set_update_policy (UPDATE_DISCONTINUOUS);
1117                 h = manage (new HBox);
1118                 h->set_spacing (4);
1119                 h->pack_start (*l, false, false);
1120                 h->pack_start (_capture_slider, true, true);
1121
1122                 _box->pack_start (*h, false, false);
1123
1124                 _capture_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &BufferingOptions::capture_changed));
1125                 _playback_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &BufferingOptions::playback_changed));
1126         }
1127
1128         void parameter_changed (string const & p)
1129         {
1130                 if (p == "buffering-preset") {
1131                         switch (_rc_config->get_buffering_preset()) {
1132                         case Small:
1133                                 _playback_slider.set_sensitive (false);
1134                                 _capture_slider.set_sensitive (false);
1135                                 _buffering_presets_combo.set_active (0);
1136                                 break;
1137                         case Medium:
1138                                 _playback_slider.set_sensitive (false);
1139                                 _capture_slider.set_sensitive (false);
1140                                 _buffering_presets_combo.set_active (1);
1141                                 break;
1142                         case Large:
1143                                 _playback_slider.set_sensitive (false);
1144                                 _capture_slider.set_sensitive (false);
1145                                 _buffering_presets_combo.set_active (2);
1146                                 break;
1147                         case Custom:
1148                                 _playback_slider.set_sensitive (true);
1149                                 _capture_slider.set_sensitive (true);
1150                                 _buffering_presets_combo.set_active (3);
1151                                 break;
1152                         }
1153                 }
1154
1155                 if (p == "playback-buffer-seconds") {
1156                         _playback_adjustment.set_value (_rc_config->get_audio_playback_buffer_seconds());
1157                 } else if (p == "capture-buffer-seconds") {
1158                         _capture_adjustment.set_value (_rc_config->get_audio_capture_buffer_seconds());
1159                 }
1160         }
1161
1162         void set_state_from_config ()
1163         {
1164                 parameter_changed ("buffering-preset");
1165                 parameter_changed ("playback-buffer-seconds");
1166                 parameter_changed ("capture-buffer-seconds");
1167         }
1168
1169 private:
1170
1171         void preset_changed ()
1172         {
1173                 int index = _buffering_presets_combo.get_active_row_number ();
1174                 if (index < 0) {
1175                         return;
1176                 }
1177                 switch (index) {
1178                 case 0:
1179                         _rc_config->set_buffering_preset (Small);
1180                         break;
1181                 case 1:
1182                         _rc_config->set_buffering_preset (Medium);
1183                         break;
1184                 case 2:
1185                         _rc_config->set_buffering_preset (Large);
1186                         break;
1187                 case 3:
1188                         _rc_config->set_buffering_preset (Custom);
1189                         break;
1190                 default:
1191                         error << string_compose (_("programming error: unknown buffering preset string, index = %1"), index) << endmsg;
1192                         break;
1193                 }
1194         }
1195         
1196         void playback_changed ()
1197         {
1198                 _rc_config->set_audio_playback_buffer_seconds ((long) _playback_adjustment.get_value());
1199         }
1200
1201         void capture_changed ()
1202         {
1203                 _rc_config->set_audio_capture_buffer_seconds ((long) _capture_adjustment.get_value());
1204         }
1205
1206         RCConfiguration* _rc_config;
1207         Adjustment _playback_adjustment;
1208         Adjustment _capture_adjustment;
1209         HScale _playback_slider;
1210         HScale _capture_slider;
1211         ComboBoxText _buffering_presets_combo;
1212 };
1213
1214 class ControlSurfacesOptions : public OptionEditorBox
1215 {
1216 public:
1217         ControlSurfacesOptions (Gtk::Window& parent)
1218                 : _parent (parent)
1219                 , _ignore_view_change (0)
1220         {
1221                 _store = ListStore::create (_model);
1222                 _view.set_model (_store);
1223                 _view.append_column (_("Control Surface Protocol"), _model.name);
1224                 _view.get_column(0)->set_resizable (true);
1225                 _view.get_column(0)->set_expand (true);
1226                 _view.append_column_editable (_("Enabled"), _model.enabled);
1227                 _view.append_column_editable (_("Feedback"), _model.feedback);
1228
1229                 _box->pack_start (_view, false, false);
1230
1231                 Label* label = manage (new Label);
1232                 label->set_markup (string_compose (X_("<i>%1</i>"), _("Double-click on a name to edit settings for an enabled protocol")));
1233
1234                 _box->pack_start (*label, false, false);
1235                 label->show ();
1236
1237                 ControlProtocolManager& m = ControlProtocolManager::instance ();
1238                 m.ProtocolStatusChange.connect (protocol_status_connection, MISSING_INVALIDATOR,
1239                                                 boost::bind (&ControlSurfacesOptions::protocol_status_changed, this, _1), gui_context());
1240
1241                 _store->signal_row_changed().connect (sigc::mem_fun (*this, &ControlSurfacesOptions::view_changed));
1242                 _view.signal_button_press_event().connect_notify (sigc::mem_fun(*this, &ControlSurfacesOptions::edit_clicked));
1243         }
1244
1245         void parameter_changed (std::string const &)
1246         {
1247
1248         }
1249
1250         void set_state_from_config ()
1251         {
1252                 _store->clear ();
1253
1254                 ControlProtocolManager& m = ControlProtocolManager::instance ();
1255                 for (list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
1256
1257                         if (!(*i)->mandatory) {
1258                                 TreeModel::Row r = *_store->append ();
1259                                 r[_model.name] = (*i)->name;
1260                                 r[_model.enabled] = ((*i)->protocol || (*i)->requested);
1261                                 r[_model.feedback] = ((*i)->protocol && (*i)->protocol->get_feedback ());
1262                                 r[_model.protocol_info] = *i;
1263                         }
1264                 }
1265         }
1266
1267 private:
1268
1269         void protocol_status_changed (ControlProtocolInfo* cpi) {
1270                 /* find the row */
1271                 TreeModel::Children rows = _store->children();
1272                 
1273                 for (TreeModel::Children::iterator x = rows.begin(); x != rows.end(); ++x) {
1274                         string n = ((*x)[_model.name]);
1275
1276                         if ((*x)[_model.protocol_info] == cpi) {
1277                                 _ignore_view_change++;
1278                                 (*x)[_model.enabled] = (cpi->protocol || cpi->requested);
1279                                 _ignore_view_change--;
1280                                 break;
1281                         }
1282                 }
1283         }
1284
1285         void view_changed (TreeModel::Path const &, TreeModel::iterator const & i)
1286         {
1287                 TreeModel::Row r = *i;
1288
1289                 if (_ignore_view_change) {
1290                         return;
1291                 }
1292
1293                 ControlProtocolInfo* cpi = r[_model.protocol_info];
1294                 if (!cpi) {
1295                         return;
1296                 }
1297
1298                 bool const was_enabled = (cpi->protocol != 0);
1299                 bool const is_enabled = r[_model.enabled];
1300
1301
1302                 if (was_enabled != is_enabled) {
1303
1304                         if (!was_enabled) {
1305                                 ControlProtocolManager::instance().activate (*cpi);
1306                         } else {
1307                                 ControlProtocolManager::instance().deactivate (*cpi);
1308                         }
1309                 }
1310
1311                 bool const was_feedback = (cpi->protocol && cpi->protocol->get_feedback ());
1312                 bool const is_feedback = r[_model.feedback];
1313
1314                 if (was_feedback != is_feedback && cpi->protocol) {
1315                         cpi->protocol->set_feedback (is_feedback);
1316                 }
1317         }
1318
1319         void edit_clicked (GdkEventButton* ev)
1320         {
1321                 if (ev->type != GDK_2BUTTON_PRESS) {
1322                         return;
1323                 }
1324
1325                 std::string name;
1326                 ControlProtocolInfo* cpi;
1327                 TreeModel::Row row;
1328
1329                 row = *(_view.get_selection()->get_selected());
1330                 if (!row[_model.enabled]) {
1331                         return;
1332                 }
1333                 cpi = row[_model.protocol_info];
1334                 if (!cpi || !cpi->protocol || !cpi->protocol->has_editor ()) {
1335                         return;
1336                 }
1337                 Box* box = (Box*) cpi->protocol->get_gui ();
1338                 if (!box) {
1339                         return;
1340                 }
1341                 if (box->get_parent()) {
1342                         static_cast<ArdourWindow*>(box->get_parent())->present();
1343                         return;
1344                 }
1345                 string title = row[_model.name];
1346                 /* once created, the window is managed by the surface itself (as ->get_parent())
1347                  * Surface's tear_down_gui() is called on session close, when de-activating
1348                  * or re-initializing a surface.
1349                  * tear_down_gui() hides an deletes the Window if it exists.
1350                  */
1351                 ArdourWindow* win = new ArdourWindow (_parent, title);
1352                 win->set_title ("Control Protocol Options");
1353                 win->add (*box);
1354                 box->show ();
1355                 win->present ();
1356         }
1357
1358         class ControlSurfacesModelColumns : public TreeModelColumnRecord
1359         {
1360         public:
1361
1362                 ControlSurfacesModelColumns ()
1363                 {
1364                         add (name);
1365                         add (enabled);
1366                         add (feedback);
1367                         add (protocol_info);
1368                 }
1369
1370                 TreeModelColumn<string> name;
1371                 TreeModelColumn<bool> enabled;
1372                 TreeModelColumn<bool> feedback;
1373                 TreeModelColumn<ControlProtocolInfo*> protocol_info;
1374         };
1375
1376         Glib::RefPtr<ListStore> _store;
1377         ControlSurfacesModelColumns _model;
1378         TreeView _view;
1379         Gtk::Window& _parent;
1380         PBD::ScopedConnection protocol_status_connection;
1381         uint32_t _ignore_view_change;
1382 };
1383
1384 class VideoTimelineOptions : public OptionEditorBox
1385 {
1386 public:
1387         VideoTimelineOptions (RCConfiguration* c)
1388                 : _rc_config (c)
1389                 , _show_video_export_info_button (_("Show Video Export Info before export"))
1390                 , _show_video_server_dialog_button (_("Show Video Server Startup Dialog"))
1391                 , _video_advanced_setup_button (_("Advanced Setup (remote video server)"))
1392         {
1393                 Table* t = manage (new Table (2, 6));
1394                 t->set_spacings (4);
1395
1396                 t->attach (_video_advanced_setup_button, 0, 2, 0, 1);
1397                 _video_advanced_setup_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::video_advanced_setup_toggled));
1398                 Gtkmm2ext::UI::instance()->set_tip (_video_advanced_setup_button,
1399                                             _("<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."));
1400
1401                 Label* l = manage (new Label (_("Video Server URL:")));
1402                 l->set_alignment (0, 0.5);
1403                 t->attach (*l, 0, 1, 1, 2, FILL);
1404                 t->attach (_video_server_url_entry, 1, 2, 1, 2, FILL);
1405                 Gtkmm2ext::UI::instance()->set_tip (_video_server_url_entry,
1406                                             _("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"));
1407
1408                 l = manage (new Label (_("Video Folder:")));
1409                 l->set_alignment (0, 0.5);
1410                 t->attach (*l, 0, 1, 2, 3, FILL);
1411                 t->attach (_video_server_docroot_entry, 1, 2, 2, 3);
1412                 Gtkmm2ext::UI::instance()->set_tip (_video_server_docroot_entry,
1413                                             _("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."));
1414
1415                 /* small vspace  y=3..4 */
1416
1417                 t->attach (_show_video_export_info_button, 0, 2, 4, 5);
1418                 _show_video_export_info_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::show_video_export_info_toggled));
1419                 Gtkmm2ext::UI::instance()->set_tip (_show_video_export_info_button,
1420                                             _("<b>When enabled</b> an information window with details is displayed before the video-export dialog."));
1421
1422                 t->attach (_show_video_server_dialog_button, 0, 2, 5, 6);
1423                 _show_video_server_dialog_button.signal_toggled().connect (sigc::mem_fun (*this, &VideoTimelineOptions::show_video_server_dialog_toggled));
1424                 Gtkmm2ext::UI::instance()->set_tip (_show_video_server_dialog_button,
1425                                             _("<b>When enabled</b> the video server is never launched automatically without confirmation"));
1426
1427                 _video_server_url_entry.signal_changed().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_url_changed));
1428                 _video_server_url_entry.signal_activate().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_url_changed));
1429                 _video_server_docroot_entry.signal_changed().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_docroot_changed));
1430                 _video_server_docroot_entry.signal_activate().connect (sigc::mem_fun(*this, &VideoTimelineOptions::server_docroot_changed));
1431
1432                 _box->pack_start (*t,true,true);
1433         }
1434
1435         void server_url_changed ()
1436         {
1437                 _rc_config->set_video_server_url (_video_server_url_entry.get_text());
1438         }
1439
1440         void server_docroot_changed ()
1441         {
1442                 _rc_config->set_video_server_docroot (_video_server_docroot_entry.get_text());
1443         }
1444
1445         void show_video_export_info_toggled ()
1446         {
1447                 bool const x = _show_video_export_info_button.get_active ();
1448                 _rc_config->set_show_video_export_info (x);
1449         }
1450
1451         void show_video_server_dialog_toggled ()
1452         {
1453                 bool const x = _show_video_server_dialog_button.get_active ();
1454                 _rc_config->set_show_video_server_dialog (x);
1455         }
1456
1457         void video_advanced_setup_toggled ()
1458         {
1459                 bool const x = _video_advanced_setup_button.get_active ();
1460                 _rc_config->set_video_advanced_setup(x);
1461         }
1462
1463         void parameter_changed (string const & p)
1464         {
1465                 if (p == "video-server-url") {
1466                         _video_server_url_entry.set_text (_rc_config->get_video_server_url());
1467                 } else if (p == "video-server-docroot") {
1468                         _video_server_docroot_entry.set_text (_rc_config->get_video_server_docroot());
1469                 } else if (p == "show-video-export-info") {
1470                         bool const x = _rc_config->get_show_video_export_info();
1471                         _show_video_export_info_button.set_active (x);
1472                 } else if (p == "show-video-server-dialog") {
1473                         bool const x = _rc_config->get_show_video_server_dialog();
1474                         _show_video_server_dialog_button.set_active (x);
1475                 } else if (p == "video-advanced-setup") {
1476                         bool const x = _rc_config->get_video_advanced_setup();
1477                         _video_advanced_setup_button.set_active(x);
1478                         _video_server_docroot_entry.set_sensitive(x);
1479                         _video_server_url_entry.set_sensitive(x);
1480                 }
1481         }
1482
1483         void set_state_from_config ()
1484         {
1485                 parameter_changed ("video-server-url");
1486                 parameter_changed ("video-server-docroot");
1487                 parameter_changed ("video-monitor-setup-dialog");
1488                 parameter_changed ("show-video-export-info");
1489                 parameter_changed ("show-video-server-dialog");
1490                 parameter_changed ("video-advanced-setup");
1491         }
1492
1493 private:
1494         RCConfiguration* _rc_config;
1495         Entry _video_server_url_entry;
1496         Entry _video_server_docroot_entry;
1497         CheckButton _show_video_export_info_button;
1498         CheckButton _show_video_server_dialog_button;
1499         CheckButton _video_advanced_setup_button;
1500 };
1501
1502 class PluginOptions : public OptionEditorBox
1503 {
1504 public:
1505         PluginOptions (RCConfiguration* c)
1506                 : _rc_config (c)
1507                 , _display_plugin_scan_progress (_("Always Display Plugin Scan Progress"))
1508                 , _discover_vst_on_start (_("Scan for [new] VST Plugins on Application Start"))
1509                 , _discover_au_on_start (_("Scan for AudioUnit Plugins on Application Start"))
1510                 , _verbose_plugin_scan (_("Verbose Plugin Scan"))
1511                 , _timeout_adjustment (0, 0, 3000, 50, 50)
1512                 , _timeout_slider (_timeout_adjustment)
1513         {
1514                 Label *l;
1515                 std::stringstream ss;
1516                 Table* t = manage (new Table (2, 6));
1517                 t->set_spacings (4);
1518                 Button* b;
1519                 int n = 0;
1520
1521                 ss << "<b>" << _("General") << "</b>";
1522                 l = manage (left_aligned_label (ss.str()));
1523                 l->set_use_markup (true);
1524                 t->attach (*manage (new Label ("")), 0, 3, n, n+1, FILL | EXPAND); ++n;
1525                 t->attach (*l, 0, 2, n, n+1, FILL | EXPAND); ++n;
1526
1527                 b = manage (new Button (_("Scan for Plugins")));
1528                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::refresh_clicked));
1529                 t->attach (*b, 0, 2, n, n+1, FILL); ++n;
1530
1531                 t->attach (_display_plugin_scan_progress, 0, 2, n, n+1); ++n;
1532                 _display_plugin_scan_progress.signal_toggled().connect (sigc::mem_fun (*this, &PluginOptions::display_plugin_scan_progress_toggled));
1533                 Gtkmm2ext::UI::instance()->set_tip (_display_plugin_scan_progress,
1534                                             _("<b>When enabled</b> a popup window showing plugin scan progress is displayed for indexing (cache load) and discovery (detect new plugins)"));
1535
1536 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
1537                 _timeout_slider.set_digits (0);
1538                 _timeout_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &PluginOptions::timeout_changed));
1539
1540                 Gtkmm2ext::UI::instance()->set_tip(_timeout_slider,
1541                          _("Specify the default timeout for plugin instantiation in 1/10 seconds. Plugins that require more time to load will be blacklisted. A value of 0 disables the timeout."));
1542
1543                 l = manage (left_aligned_label (_("Scan Time Out [deciseconds]")));;
1544                 HBox* h = manage (new HBox);
1545                 h->set_spacing (4);
1546                 h->pack_start (*l, false, false);
1547                 h->pack_start (_timeout_slider, true, true);
1548                 t->attach (*h, 0, 2, n, n+1); ++n;
1549
1550                 ss.str("");
1551                 ss << "<b>" << _("VST") << "</b>";
1552                 l = manage (left_aligned_label (ss.str()));
1553                 l->set_use_markup (true);
1554                 t->attach (*manage (new Label ("")), 0, 3, n, n+1, FILL | EXPAND); ++n;
1555                 t->attach (*l, 0, 2, n, n+1, FILL | EXPAND); ++n;
1556
1557                 b = manage (new Button (_("Clear VST Cache")));
1558                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::clear_vst_cache_clicked));
1559                 t->attach (*b, 0, 1, n, n+1, FILL);
1560
1561                 b = manage (new Button (_("Clear VST Blacklist")));
1562                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::clear_vst_blacklist_clicked));
1563                 t->attach (*b, 1, 2, n, n+1, FILL);
1564                 ++n;
1565
1566                 t->attach (_discover_vst_on_start, 0, 2, n, n+1); ++n;
1567                 _discover_vst_on_start.signal_toggled().connect (sigc::mem_fun (*this, &PluginOptions::discover_vst_on_start_toggled));
1568                 Gtkmm2ext::UI::instance()->set_tip (_discover_vst_on_start,
1569                                             _("<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"));
1570
1571 #ifdef LXVST_SUPPORT
1572                 t->attach (*manage (right_aligned_label (_("Linux VST Path:"))), 0, 1, n, n+1);
1573                 b = manage (new Button (_("Edit")));
1574                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::edit_lxvst_path_clicked));
1575                 t->attach (*b, 1, 2, n, n+1, FILL); ++n;
1576 #endif
1577
1578 #ifdef WINDOWS_VST_SUPPORT
1579                 t->attach (*manage (right_aligned_label (_("Windows VST Path:"))), 0, 1, n, n+1);
1580                 b = manage (new Button (_("Edit")));
1581                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::edit_vst_path_clicked));
1582                 t->attach (*b, 1, 2, n, n+1, FILL); ++n;
1583
1584                 // currently verbose logging is only implemented for Windows VST.
1585                 t->attach (_verbose_plugin_scan, 0, 2, n, n+1); ++n;
1586                 _verbose_plugin_scan.signal_toggled().connect (sigc::mem_fun (*this, &PluginOptions::verbose_plugin_scan_toggled));
1587                 Gtkmm2ext::UI::instance()->set_tip (_verbose_plugin_scan,
1588                                             _("<b>When enabled</b> additional information for every plugin is added to the Log Window."));
1589 #endif
1590 #endif // any VST
1591
1592 #ifdef AUDIOUNIT_SUPPORT
1593                 ss.str("");
1594                 ss << "<b>" << _("Audio Unit") << "</b>";
1595                 l = manage (left_aligned_label (ss.str()));
1596                 l->set_use_markup (true);
1597                 t->attach (*manage (new Label ("")), 0, 3, n, n+1, FILL | EXPAND); ++n;
1598                 t->attach (*l, 0, 2, n, n+1, FILL | EXPAND); ++n;
1599
1600                 t->attach (_discover_au_on_start, 0, 2, n, n+1); ++n;
1601                 _discover_au_on_start.signal_toggled().connect (sigc::mem_fun (*this, &PluginOptions::discover_au_on_start_toggled));
1602                 Gtkmm2ext::UI::instance()->set_tip (_discover_au_on_start,
1603                                             _("<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."));
1604
1605                 ++n;
1606                 b = manage (new Button (_("Clear AU Cache")));
1607                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::clear_au_cache_clicked));
1608                 t->attach (*b, 0, 1, n, n+1, FILL);
1609
1610                 b = manage (new Button (_("Clear AU Blacklist")));
1611                 b->signal_clicked().connect (sigc::mem_fun (*this, &PluginOptions::clear_au_blacklist_clicked));
1612                 t->attach (*b, 1, 2, n, n+1, FILL);
1613                 ++n;
1614 #endif
1615
1616                 _box->pack_start (*t,true,true);
1617         }
1618
1619         void parameter_changed (string const & p) {
1620                 if (p == "show-plugin-scan-window") {
1621                         bool const x = UIConfiguration::instance().get_show_plugin_scan_window();
1622                         _display_plugin_scan_progress.set_active (x);
1623                 }
1624                 else if (p == "discover-vst-on-start") {
1625                         bool const x = _rc_config->get_discover_vst_on_start();
1626                         _discover_vst_on_start.set_active (x);
1627                 }
1628                 else if (p == "vst-scan-timeout") {
1629                         int const x = _rc_config->get_vst_scan_timeout();
1630                         _timeout_adjustment.set_value (x);
1631                 }
1632                 else if (p == "discover-audio-units") {
1633                         bool const x = _rc_config->get_discover_audio_units();
1634                         _discover_au_on_start.set_active (x);
1635                 }
1636                 else if (p == "verbose-plugin-scan") {
1637                         bool const x = _rc_config->get_verbose_plugin_scan();
1638                         _verbose_plugin_scan.set_active (x);
1639                 }
1640         }
1641
1642         void set_state_from_config () {
1643                 parameter_changed ("show-plugin-scan-window");
1644                 parameter_changed ("discover-vst-on-start");
1645                 parameter_changed ("vst-scan-timeout");
1646                 parameter_changed ("discover-audio-units");
1647                 parameter_changed ("verbose-plugin-scan");
1648         }
1649
1650 private:
1651         RCConfiguration* _rc_config;
1652         CheckButton _display_plugin_scan_progress;
1653         CheckButton _discover_vst_on_start;
1654         CheckButton _discover_au_on_start;
1655         CheckButton _verbose_plugin_scan;
1656         Adjustment _timeout_adjustment;
1657         HScale _timeout_slider;
1658
1659         void display_plugin_scan_progress_toggled () {
1660                 bool const x = _display_plugin_scan_progress.get_active();
1661                 UIConfiguration::instance().set_show_plugin_scan_window(x);
1662         }
1663
1664         void discover_vst_on_start_toggled () {
1665                 bool const x = _discover_vst_on_start.get_active();
1666                 _rc_config->set_discover_vst_on_start(x);
1667         }
1668
1669         void discover_au_on_start_toggled () {
1670                 bool const x = _discover_au_on_start.get_active();
1671                 _rc_config->set_discover_audio_units(x);
1672         }
1673
1674         void verbose_plugin_scan_toggled () {
1675                 bool const x = _verbose_plugin_scan.get_active();
1676                 _rc_config->set_verbose_plugin_scan(x);
1677         }
1678
1679         void timeout_changed () {
1680                 int x = floor(_timeout_adjustment.get_value());
1681                 _rc_config->set_vst_scan_timeout(x);
1682         }
1683
1684         void clear_vst_cache_clicked () {
1685                 PluginManager::instance().clear_vst_cache();
1686         }
1687
1688         void clear_vst_blacklist_clicked () {
1689                 PluginManager::instance().clear_vst_blacklist();
1690         }
1691
1692         void clear_au_cache_clicked () {
1693                 PluginManager::instance().clear_au_cache();
1694         }
1695
1696         void clear_au_blacklist_clicked () {
1697                 PluginManager::instance().clear_au_blacklist();
1698         }
1699
1700
1701         void edit_vst_path_clicked () {
1702                 Gtkmm2ext::PathsDialog *pd = new Gtkmm2ext::PathsDialog (
1703                                 _("Set Windows VST Search Path"),
1704                                 _rc_config->get_plugin_path_vst(),
1705                                 PluginManager::instance().get_default_windows_vst_path()
1706                         );
1707                 ResponseType r = (ResponseType) pd->run ();
1708                 pd->hide();
1709                 if (r == RESPONSE_ACCEPT) {
1710                         _rc_config->set_plugin_path_vst(pd->get_serialized_paths());
1711                 }
1712                 delete pd;
1713         }
1714
1715         // todo consolidate with edit_vst_path_clicked..
1716         void edit_lxvst_path_clicked () {
1717                 Gtkmm2ext::PathsDialog *pd = new Gtkmm2ext::PathsDialog (
1718                                 _("Set Linux VST Search Path"),
1719                                 _rc_config->get_plugin_path_lxvst(),
1720                                 PluginManager::instance().get_default_lxvst_path()
1721                                 );
1722                 ResponseType r = (ResponseType) pd->run ();
1723                 pd->hide();
1724                 if (r == RESPONSE_ACCEPT) {
1725                         _rc_config->set_plugin_path_lxvst(pd->get_serialized_paths());
1726                 }
1727                 delete pd;
1728         }
1729
1730         void refresh_clicked () {
1731                 PluginManager::instance().refresh();
1732         }
1733 };
1734
1735
1736 /** A class which allows control of visibility of some editor components usign
1737  *  a VisibilityGroup.  The caller should pass in a `dummy' VisibilityGroup
1738  *  which has the correct members, but with null widget pointers.  This
1739  *  class allows the user to set visibility of the members, the details
1740  *  of which are stored in a configuration variable which can be watched
1741  *  by parts of the editor that actually contain the widgets whose visibility
1742  *  is being controlled.
1743  */
1744
1745 class VisibilityOption : public Option
1746 {
1747 public:
1748         /** @param name User-visible name for this group.
1749          *  @param g `Dummy' VisibilityGroup (as described above).
1750          *  @param get Method to get the value of the appropriate configuration variable.
1751          *  @param set Method to set the value of the appropriate configuration variable.
1752          */
1753         VisibilityOption (string name, VisibilityGroup* g, sigc::slot<string> get, sigc::slot<bool, string> set)
1754                 : Option (g->get_state_name(), name)
1755                 , _heading (name)
1756                 , _visibility_group (g)
1757                 , _get (get)
1758                 , _set (set)
1759         {
1760                 /* Watch for changes made by the user to our members */
1761                 _visibility_group->VisibilityChanged.connect_same_thread (
1762                         _visibility_group_connection, sigc::bind (&VisibilityOption::changed, this)
1763                         );
1764         }
1765
1766         void set_state_from_config ()
1767         {
1768                 /* Set our state from the current configuration */
1769                 _visibility_group->set_state (_get ());
1770         }
1771
1772         void add_to_page (OptionEditorPage* p)
1773         {
1774                 _heading.add_to_page (p);
1775                 add_widget_to_page (p, _visibility_group->list_view ());
1776         }
1777
1778         Gtk::Widget& tip_widget() { return *_visibility_group->list_view (); }
1779
1780 private:
1781         void changed ()
1782         {
1783                 /* The user has changed something, so reflect this change
1784                    in the RCConfiguration.
1785                 */
1786                 _set (_visibility_group->get_state_value ());
1787         }
1788         
1789         OptionEditorHeading _heading;
1790         VisibilityGroup* _visibility_group;
1791         sigc::slot<std::string> _get;
1792         sigc::slot<bool, std::string> _set;
1793         PBD::ScopedConnection _visibility_group_connection;
1794 };
1795
1796
1797
1798 RCOptionEditor::RCOptionEditor ()
1799         : OptionEditor (Config, string_compose (_("%1 Preferences"), PROGRAM_NAME))
1800         , _rc_config (Config)
1801         , _mixer_strip_visibility ("mixer-element-visibility")
1802 {
1803         /* MISC */
1804
1805         uint32_t hwcpus = hardware_concurrency ();
1806         BoolOption* bo;
1807         BoolComboOption* bco;
1808
1809         if (hwcpus > 1) {
1810                 add_option (_("Misc"), new OptionEditorHeading (_("DSP CPU Utilization")));
1811
1812                 ComboOption<int32_t>* procs = new ComboOption<int32_t> (
1813                         "processor-usage",
1814                         _("Signal processing uses"),
1815                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_processor_usage),
1816                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_processor_usage)
1817                         );
1818
1819                 procs->add (-1, _("all but one processor"));
1820                 procs->add (0, _("all available processors"));
1821
1822                 for (uint32_t i = 1; i <= hwcpus; ++i) {
1823                         procs->add (i, string_compose (_("%1 processors"), i));
1824                 }
1825
1826                 procs->set_note (string_compose (_("This setting will only take effect when %1 is restarted."), PROGRAM_NAME));
1827
1828                 add_option (_("Misc"), procs);
1829         }
1830
1831         add_option (_("Misc"), new OptionEditorHeading (S_("Options|Undo")));
1832
1833         add_option (_("Misc"), new UndoOptions (_rc_config));
1834
1835         add_option (_("Misc"),
1836              new BoolOption (
1837                      "verify-remove-last-capture",
1838                      _("Verify removal of last capture"),
1839                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_verify_remove_last_capture),
1840                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_verify_remove_last_capture)
1841                      ));
1842
1843         add_option (_("Misc"),
1844              new BoolOption (
1845                      "periodic-safety-backups",
1846                      _("Automatically save the session file at regular intervals"),
1847                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_periodic_safety_backups),
1848                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_periodic_safety_backups)
1849                      ));
1850
1851         add_option (_("Misc"), new OptionEditorHeading (_("Session Management")));
1852
1853         add_option (_("Misc"),
1854              new BoolOption (
1855                      "only-copy-imported-files",
1856                      _("Always copy imported files"),
1857                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_only_copy_imported_files),
1858                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_only_copy_imported_files)
1859                      ));
1860
1861         add_option (_("Misc"), new DirectoryOption (
1862                             X_("default-session-parent-dir"),
1863                             _("Default folder for new sessions:"),
1864                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_default_session_parent_dir),
1865                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_default_session_parent_dir)
1866                             ));
1867
1868         add_option (_("Misc"),
1869              new SpinOption<uint32_t> (
1870                      "max-recent-sessions",
1871                      _("Maximum number of recent sessions"),
1872                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_max_recent_sessions),
1873                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_max_recent_sessions),
1874                      0, 1000, 1, 20
1875                      ));
1876
1877         add_option (_("Misc"), new OptionEditorHeading (_("Click")));
1878
1879         add_option (_("Misc"), new ClickOptions (_rc_config, this));
1880
1881         add_option (_("Misc"),
1882              new FaderOption (
1883                      "click-gain",
1884                      _("Click gain level"),
1885                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_click_gain),
1886                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_click_gain)
1887                      ));
1888
1889         add_option (_("Misc"), new OptionEditorHeading (_("Automation")));
1890
1891         add_option (_("Misc"),
1892              new SpinOption<double> (
1893                      "automation-thinning-factor",
1894                      _("Thinning factor (larger value => less data)"),
1895                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_thinning_factor),
1896                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_thinning_factor),
1897                      0, 1000, 1, 20
1898                      ));
1899
1900         add_option (_("Misc"),
1901              new SpinOption<double> (
1902                      "automation-interval-msecs",
1903                      _("Automation sampling interval (milliseconds)"),
1904                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_interval_msecs),
1905                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_interval_msecs),
1906                      1, 1000, 1, 20
1907                      ));
1908
1909         /* TRANSPORT */
1910
1911         add_option (_("Transport"), new OptionEditorHeading (S_("Transport Options")));
1912
1913         BoolOption* tsf;
1914
1915         tsf = new BoolOption (
1916                      "latched-record-enable",
1917                      _("Keep record-enable engaged on stop"),
1918                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_latched_record_enable),
1919                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_latched_record_enable)
1920                      );
1921         // Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _(""));
1922         add_option (_("Transport"), tsf);
1923
1924         tsf = new BoolOption (
1925                      "loop-is-mode",
1926                      _("Play loop is a transport mode"),
1927                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_loop_is_mode),
1928                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_loop_is_mode)
1929                      );
1930         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), 
1931                                             (_("<b>When enabled</b> the loop button does not start playback but forces playback to always play the loop\n\n"
1932                                                "<b>When disabled</b> the loop button starts playing the loop, but stop then cancels loop playback")));
1933         add_option (_("Transport"), tsf);
1934         
1935         tsf = new BoolOption (
1936                      "stop-recording-on-xrun",
1937                      _("Stop recording when an xrun occurs"),
1938                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_recording_on_xrun),
1939                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_recording_on_xrun)
1940                      );
1941         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), 
1942                                             string_compose (_("<b>When enabled</b> %1 will stop recording if an over- or underrun is detected by the audio engine"),
1943                                                             PROGRAM_NAME));
1944         add_option (_("Transport"), tsf);
1945
1946         tsf = new BoolOption (
1947                      "create-xrun-marker",
1948                      _("Create markers where xruns occur"),
1949                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_create_xrun_marker),
1950                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_create_xrun_marker)
1951                      );
1952         // Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _(""));
1953         add_option (_("Transport"), tsf);
1954
1955         tsf = new BoolOption (
1956                      "stop-at-session-end",
1957                      _("Stop at the end of the session"),
1958                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_at_session_end),
1959                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_at_session_end)
1960                      );
1961         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), 
1962                                             string_compose (_("<b>When enabled</b> if %1 is <b>not recording</b>, it will stop the transport "
1963                                                               "when it reaches the current session end marker\n\n"
1964                                                               "<b>When disabled</b> %1 will continue to roll past the session end marker at all times"),
1965                                                             PROGRAM_NAME));
1966         add_option (_("Transport"), tsf);
1967
1968         tsf = new BoolOption (
1969                      "seamless-loop",
1970                      _("Do seamless looping (not possible when slaved to MTC, LTC etc)"),
1971                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_seamless_loop),
1972                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_seamless_loop)
1973                      );
1974         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), 
1975                                             string_compose (_("<b>When enabled</b> this will loop by reading ahead and wrapping around at the loop point, "
1976                                                               "preventing any need to do a transport locate at the end of the loop\n\n"
1977                                                               "<b>When disabled</b> looping is done by locating back to the start of the loop when %1 reaches the end "
1978                                                               "which will often cause a small click or delay"), PROGRAM_NAME));
1979         add_option (_("Transport"), tsf);
1980
1981         tsf = new BoolOption (
1982                      "disable-disarm-during-roll",
1983                      _("Disable per-track record disarm while rolling"),
1984                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_disable_disarm_during_roll),
1985                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_disable_disarm_during_roll)
1986                      );
1987         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"));
1988         add_option (_("Transport"), tsf);
1989
1990         tsf = new BoolOption (
1991                      "quieten_at_speed",
1992                      _("12dB gain reduction during fast-forward and fast-rewind"),
1993                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_quieten_at_speed),
1994                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_quieten_at_speed)
1995                      );
1996         Gtkmm2ext::UI::instance()->set_tip (tsf->tip_widget(), _("This will reduce the unpleasant increase in perceived volume "
1997                                                    "that occurs when fast-forwarding or rewinding through some kinds of audio"));
1998         add_option (_("Transport"), tsf);
1999
2000         add_option (_("Transport"), new OptionEditorHeading (S_("Sync/Slave")));
2001
2002         _sync_source = new ComboOption<SyncSource> (
2003                 "sync-source",
2004                 _("External timecode source"),
2005                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_sync_source),
2006                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_sync_source)
2007                 );
2008
2009         add_option (_("Transport"), _sync_source);
2010
2011         _sync_framerate = new BoolOption (
2012                      "timecode-sync-frame-rate",
2013                      _("Match session video frame rate to external timecode"),
2014                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_sync_frame_rate),
2015                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_sync_frame_rate)
2016                      );
2017         Gtkmm2ext::UI::instance()->set_tip 
2018                 (_sync_framerate->tip_widget(),
2019                  string_compose (_("This option controls the value of the video frame rate <i>while chasing</i> an external timecode source.\n\n"
2020                                    "<b>When enabled</b> the session video frame rate will be changed to match that of the selected external timecode source.\n\n"
2021                                    "<b>When disabled</b> the session video frame rate will not be changed to match that of the selected external timecode source."
2022                                    "Instead the frame rate indication in the main clock will flash red and %1 will convert between the external "
2023                                    "timecode standard and the session standard."), PROGRAM_NAME));
2024
2025         add_option (_("Transport"), _sync_framerate);
2026
2027         _sync_genlock = new BoolOption (
2028                 "timecode-source-is-synced",
2029                 _("Sync-lock timecode to clock (disable drift compensation)"),
2030                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_is_synced),
2031                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_is_synced)
2032                 );
2033         Gtkmm2ext::UI::instance()->set_tip 
2034                 (_sync_genlock->tip_widget(),
2035                  string_compose (_("<b>When enabled</b> %1 will never varispeed when slaved to external timecode. "
2036                                    "Sync Lock indicates that the selected external timecode source shares clock-sync "
2037                                    "(Black &amp; Burst, Wordclock, etc) with the audio interface. "
2038                                    "This option disables drift compensation. The transport speed is fixed at 1.0. "
2039                                    "Vari-speed LTC will be ignored and cause drift."
2040                                    "\n\n"
2041                                    "<b>When disabled</b> %1 will compensate for potential drift, regardless if the "
2042                                    "timecode sources shares clock sync."
2043                                   ), PROGRAM_NAME));
2044
2045
2046         add_option (_("Transport"), _sync_genlock);
2047
2048         _sync_source_2997 = new BoolOption (
2049                 "timecode-source-2997",
2050                 _("Lock to 29.9700 fps instead of 30000/1001"),
2051                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_timecode_source_2997),
2052                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_timecode_source_2997)
2053                 );
2054         Gtkmm2ext::UI::instance()->set_tip
2055                 (_sync_source_2997->tip_widget(),
2056                  _("<b>When enabled</b> the external timecode source is assumed to use 29.97 fps instead of 30000/1001.\n"
2057                          "SMPTE 12M-1999 specifies 29.97df as 30000/1001. The spec further mentions that "
2058                          "drop-frame timecode has an accumulated error of -86ms over a 24-hour period.\n"
2059                          "Drop-frame timecode would compensate exactly for a NTSC color frame rate of 30 * 0.9990 (ie 29.970000). "
2060                          "That is not the actual rate. However, some vendors use that rate - despite it being against the specs - "
2061                          "because the variant of using exactly 29.97 fps has zero timecode drift.\n"
2062                          ));
2063
2064         add_option (_("Transport"), _sync_source_2997);
2065
2066         add_option (_("Transport"), new OptionEditorHeading (S_("LTC Reader")));
2067
2068         _ltc_port = new ComboStringOption (
2069                 "ltc-source-port",
2070                 _("LTC incoming port"),
2071                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_source_port),
2072                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_source_port)
2073                 );
2074
2075         vector<string> physical_inputs;
2076         physical_inputs.push_back (_("None"));
2077         AudioEngine::instance()->get_physical_inputs (DataType::AUDIO, physical_inputs);
2078         _ltc_port->set_popdown_strings (physical_inputs);
2079
2080         populate_sync_options ();
2081
2082         add_option (_("Transport"), _ltc_port);
2083
2084         // TODO; rather disable this button than not compile it..
2085         add_option (_("Transport"), new OptionEditorHeading (S_("LTC Generator")));
2086
2087         add_option (_("Transport"),
2088                     new BoolOption (
2089                             "send-ltc",
2090                             _("Enable LTC generator"),
2091                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_ltc),
2092                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_ltc)
2093                             ));
2094
2095         _ltc_send_continuously = new BoolOption (
2096                             "ltc-send-continuously",
2097                             _("Send LTC while stopped"),
2098                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_ltc_send_continuously),
2099                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_ltc_send_continuously)
2100                             );
2101         Gtkmm2ext::UI::instance()->set_tip
2102                 (_ltc_send_continuously->tip_widget(),
2103                  string_compose (_("<b>When enabled</b> %1 will continue to send LTC information even when the transport (playhead) is not moving"), PROGRAM_NAME));
2104         add_option (_("Transport"), _ltc_send_continuously);
2105
2106         _ltc_volume_adjustment = new Gtk::Adjustment(-18, -50, 0, .5, 5);
2107         _ltc_volume_adjustment->set_value (20 * log10(_rc_config->get_ltc_output_volume()));
2108         _ltc_volume_adjustment->signal_value_changed().connect (sigc::mem_fun (*this, &RCOptionEditor::ltc_generator_volume_changed));
2109         _ltc_volume_slider = new HSliderOption("ltcvol", _("LTC generator level"), *_ltc_volume_adjustment);
2110
2111         Gtkmm2ext::UI::instance()->set_tip
2112                 (_ltc_volume_slider->tip_widget(),
2113                  _("Specify the Peak Volume of the generated LTC signal in dbFS. A good value is  0dBu ^= -18dbFS in an EBU calibrated system"));
2114
2115         add_option (_("Transport"), _ltc_volume_slider);
2116         parameter_changed ("send-ltc");
2117
2118         parameter_changed ("sync-source");
2119
2120         /* EDITOR */
2121
2122         add_option (S_("Editor"),
2123              new BoolOption (
2124                      "draggable-playhead",
2125                      _("Allow dragging of playhead"),
2126                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_draggable_playhead),
2127                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_draggable_playhead)
2128                      ));
2129
2130         add_option (_("Editor"),
2131              new BoolOption (
2132                      "automation-follows-regions",
2133                      _("Move relevant automation when audio regions are moved"),
2134                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_follows_regions),
2135                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_follows_regions)
2136                      ));
2137
2138         add_option (_("Editor"),
2139              new BoolOption (
2140                      "show-track-meters",
2141                      _("Show meters on tracks in the editor"),
2142                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_track_meters),
2143                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_track_meters)
2144                      ));
2145
2146         add_option (_("Editor"),
2147              new BoolOption (
2148                      "show-editor-meter",
2149                      _("Display master-meter in the toolbar"),
2150                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_editor_meter),
2151                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_editor_meter)
2152                      ));
2153
2154         ComboOption<FadeShape>* fadeshape = new ComboOption<FadeShape> (
2155                         "default-fade-shape",
2156                         _("Default fade shape"),
2157                         sigc::mem_fun (*_rc_config,
2158                                 &RCConfiguration::get_default_fade_shape),
2159                         sigc::mem_fun (*_rc_config,
2160                                 &RCConfiguration::set_default_fade_shape)
2161                         );
2162
2163         fadeshape->add (FadeLinear,
2164                         _("Linear (for highly correlated material)"));
2165         fadeshape->add (FadeConstantPower, _("Constant power"));
2166         fadeshape->add (FadeSymmetric, _("Symmetric"));
2167         fadeshape->add (FadeSlow, _("Slow"));
2168         fadeshape->add (FadeFast, _("Fast"));
2169
2170         add_option (_("Editor"), fadeshape);
2171
2172
2173         bco = new BoolComboOption (
2174                      "use-overlap-equivalency",
2175                      _("Regions in active edit groups are edited together"),
2176                      _("whenever they overlap in time"),
2177                      _("only if they have identical length, position and origin"),
2178                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_use_overlap_equivalency),
2179                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_use_overlap_equivalency)
2180                      );
2181
2182         add_option (_("Editor"), bco);
2183
2184         ComboOption<LayerModel>* lm = new ComboOption<LayerModel> (
2185                 "layer-model",
2186                 _("Layering model"),
2187                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_layer_model),
2188                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_layer_model)
2189                 );
2190
2191         lm->add (LaterHigher, _("later is higher"));
2192         lm->add (Manual, _("manual layering"));
2193         add_option (_("Editor"), lm);
2194
2195         add_option (_("Editor"),
2196              new BoolOption (
2197                      "rubberbanding-snaps-to-grid",
2198                      _("Make rubberband selection rectangle snap to the grid"),
2199                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_rubberbanding_snaps_to_grid),
2200                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_rubberbanding_snaps_to_grid)
2201                      ));
2202
2203         add_option (_("Editor"),
2204              new BoolOption (
2205                      "show-waveforms",
2206                      _("Show waveforms in regions"),
2207                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveforms),
2208                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveforms)
2209                      ));
2210
2211         add_option (_("Editor"),
2212              new BoolComboOption (
2213                      "show-region-gain-envelopes",
2214                      _("Show gain envelopes in audio regions"),
2215                      _("in all modes"),
2216                      _("only in Draw and Internal Edit modes"),
2217                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_region_gain),
2218                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_region_gain)
2219                      ));
2220
2221         ComboOption<WaveformScale>* wfs = new ComboOption<WaveformScale> (
2222                 "waveform-scale",
2223                 _("Waveform scale"),
2224                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_scale),
2225                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_scale)
2226                 );
2227
2228         wfs->add (Linear, _("linear"));
2229         wfs->add (Logarithmic, _("logarithmic"));
2230
2231         add_option (_("Editor"), wfs);
2232
2233         ComboOption<WaveformShape>* wfsh = new ComboOption<WaveformShape> (
2234                 "waveform-shape",
2235                 _("Waveform shape"),
2236                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_shape),
2237                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_shape)
2238                 );
2239
2240         wfsh->add (Traditional, _("traditional"));
2241         wfsh->add (Rectified, _("rectified"));
2242
2243         add_option (_("Editor"), wfsh);
2244
2245         add_option (_("Editor"), new ClipLevelOptions ());
2246
2247         add_option (_("Editor"),
2248              new BoolOption (
2249                      "show-waveforms-while-recording",
2250                      _("Show waveforms for audio while it is being recorded"),
2251                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_waveforms_while_recording),
2252                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_waveforms_while_recording)
2253                      ));
2254
2255         add_option (_("Editor"),
2256                     new BoolOption (
2257                             "show-zoom-tools",
2258                             _("Show zoom toolbar"),
2259                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_zoom_tools),
2260                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_zoom_tools)
2261                             ));
2262
2263         add_option (_("Editor"),
2264                     new BoolOption (
2265                             "update-editor-during-summary-drag",
2266                             _("Update editor window during drags of the summary"),
2267                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_update_editor_during_summary_drag),
2268                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_update_editor_during_summary_drag)
2269                             ));
2270
2271         bo = new BoolOption (
2272                      "name-new-markers",
2273                      _("Name new markers"),
2274                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_name_new_markers),
2275                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_name_new_markers)
2276                 );
2277         
2278         add_option (_("Editor"), bo);
2279         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."
2280                                                                 "\n\nYou can always rename markers by right-clicking on them"));
2281
2282         add_option (_("Editor"),
2283             new BoolOption (
2284                     "autoscroll-editor",
2285                     _("Auto-scroll editor window when dragging near its edges"),
2286                     sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_autoscroll_editor),
2287                     sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_autoscroll_editor)
2288                     ));
2289
2290         ComboOption<RegionSelectionAfterSplit> *rsas = new ComboOption<RegionSelectionAfterSplit> (
2291                     "region-selection-after-split",
2292                     _("After splitting selected regions, select"),
2293                     sigc::mem_fun (*_rc_config, &RCConfiguration::get_region_selection_after_split),
2294                     sigc::mem_fun (*_rc_config, &RCConfiguration::set_region_selection_after_split));
2295
2296         // TODO: decide which of these modes are really useful
2297         rsas->add(None, _("no regions"));
2298         // rsas->add(NewlyCreatedLeft, _("newly-created regions before the split"));
2299         // rsas->add(NewlyCreatedRight, _("newly-created regions after the split"));
2300         rsas->add(NewlyCreatedBoth, _("newly-created regions"));
2301         // rsas->add(Existing, _("unmodified regions in the existing selection"));
2302         // rsas->add(ExistingNewlyCreatedLeft, _("existing selection and newly-created regions before the split"));
2303         // rsas->add(ExistingNewlyCreatedRight, _("existing selection and newly-created regions after the split"));
2304         rsas->add(ExistingNewlyCreatedBoth, _("existing selection and newly-created regions"));
2305
2306         add_option (_("Editor"), rsas);
2307
2308
2309         /* AUDIO */
2310
2311         add_option (_("Audio"), new OptionEditorHeading (_("Buffering")));
2312
2313         add_option (_("Audio"), new BufferingOptions (_rc_config));
2314
2315         add_option (_("Audio"), new OptionEditorHeading (_("Monitoring")));
2316
2317         ComboOption<MonitorModel>* mm = new ComboOption<MonitorModel> (
2318                 "monitoring-model",
2319                 _("Record monitoring handled by"),
2320                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_monitoring_model),
2321                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_monitoring_model)
2322                 );
2323
2324         if (AudioEngine::instance()->port_engine().can_monitor_input()) {
2325                 mm->add (HardwareMonitoring, _("via Audio Driver"));
2326         }
2327
2328         string prog (PROGRAM_NAME);
2329         boost::algorithm::to_lower (prog);
2330         mm->add (SoftwareMonitoring, string_compose (_("%1"), prog));
2331         mm->add (ExternalMonitoring, _("audio hardware"));
2332
2333         add_option (_("Audio"), mm);
2334
2335         add_option (_("Audio"),
2336              new BoolOption (
2337                      "tape-machine-mode",
2338                      _("Tape machine mode"),
2339                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_tape_machine_mode),
2340                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_tape_machine_mode)
2341                      ));
2342
2343         add_option (_("Audio"), new OptionEditorHeading (_("Connection of tracks and busses")));
2344
2345         add_option (_("Audio"),
2346                     new BoolOption (
2347                             "auto-connect-standard-busses",
2348                             _("Auto-connect master/monitor busses"),
2349                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_connect_standard_busses),
2350                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_connect_standard_busses)
2351                             ));
2352
2353         ComboOption<AutoConnectOption>* iac = new ComboOption<AutoConnectOption> (
2354                 "input-auto-connect",
2355                 _("Connect track inputs"),
2356                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_input_auto_connect),
2357                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_input_auto_connect)
2358                 );
2359
2360         iac->add (AutoConnectPhysical, _("automatically to physical inputs"));
2361         iac->add (ManualConnect, _("manually"));
2362
2363         add_option (_("Audio"), iac);
2364
2365         ComboOption<AutoConnectOption>* oac = new ComboOption<AutoConnectOption> (
2366                 "output-auto-connect",
2367                 _("Connect track and bus outputs"),
2368                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_output_auto_connect),
2369                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_output_auto_connect)
2370                 );
2371
2372         oac->add (AutoConnectPhysical, _("automatically to physical outputs"));
2373         oac->add (AutoConnectMaster, _("automatically to master bus"));
2374         oac->add (ManualConnect, _("manually"));
2375
2376         add_option (_("Audio"), oac);
2377
2378         add_option (_("Audio"), new OptionEditorHeading (_("Denormals")));
2379
2380         add_option (_("Audio"),
2381              new BoolOption (
2382                      "denormal-protection",
2383                      _("Use DC bias to protect against denormals"),
2384                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_protection),
2385                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_protection)
2386                      ));
2387
2388         ComboOption<DenormalModel>* dm = new ComboOption<DenormalModel> (
2389                 "denormal-model",
2390                 _("Processor handling"),
2391                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_model),
2392                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_model)
2393                 );
2394
2395         int dmsize = 1;
2396         dm->add (DenormalNone, _("no processor handling"));
2397
2398         FPU* fpu = FPU::instance();
2399
2400         if (fpu->has_flush_to_zero()) {
2401                 ++dmsize;
2402                 dm->add (DenormalFTZ, _("use FlushToZero"));
2403         } else if (_rc_config->get_denormal_model() == DenormalFTZ) {
2404                 _rc_config->set_denormal_model(DenormalNone);
2405         }
2406
2407         if (fpu->has_denormals_are_zero()) {
2408                 ++dmsize;
2409                 dm->add (DenormalDAZ, _("use DenormalsAreZero"));
2410         } else if (_rc_config->get_denormal_model() == DenormalDAZ) {
2411                 _rc_config->set_denormal_model(DenormalNone);
2412         }
2413
2414         if (fpu->has_flush_to_zero() && fpu->has_denormals_are_zero()) {
2415                 ++dmsize;
2416                 dm->add (DenormalFTZDAZ, _("use FlushToZero and DenormalsAreZero"));
2417         } else if (_rc_config->get_denormal_model() == DenormalFTZDAZ) {
2418                 _rc_config->set_denormal_model(DenormalNone);
2419         }
2420
2421         if (dmsize == 1) {
2422                 dm->set_sensitive(false);
2423         }
2424
2425         add_option (_("Audio"), dm);
2426
2427         add_option (_("Audio"), new OptionEditorHeading (_("Plugins")));
2428
2429         add_option (_("Audio"),
2430              new BoolOption (
2431                      "plugins-stop-with-transport",
2432                      _("Silence plugins when the transport is stopped"),
2433                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugins_stop_with_transport),
2434                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_plugins_stop_with_transport)
2435                      ));
2436
2437         add_option (_("Audio"),
2438              new BoolOption (
2439                      "new-plugins-active",
2440                      _("Make new plugins active"),
2441                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_new_plugins_active),
2442                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_new_plugins_active)
2443                      ));
2444
2445         add_option (_("Audio"), new OptionEditorHeading (_("Regions")));
2446
2447         add_option (_("Audio"),
2448              new BoolOption (
2449                      "auto-analyse-audio",
2450                      _("Enable automatic analysis of audio"),
2451                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_analyse_audio),
2452                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_analyse_audio)
2453                      ));
2454
2455         add_option (_("Audio"),
2456              new BoolOption (
2457                      "replicate-missing-region-channels",
2458                      _("Replicate missing region channels"),
2459                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_replicate_missing_region_channels),
2460                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_replicate_missing_region_channels)
2461                      ));
2462
2463         /* SOLO AND MUTE */
2464
2465         add_option (_("Solo / mute"), new OptionEditorHeading (_("Solo")));
2466
2467         add_option (_("Solo / mute"),
2468              new FaderOption (
2469                      "solo-mute-gain",
2470                      _("Solo-in-place mute cut (dB)"),
2471                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_gain),
2472                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_gain)
2473                      ));
2474
2475         _solo_control_is_listen_control = new BoolOption (
2476                 "solo-control-is-listen-control",
2477                 _("Solo controls are Listen controls"),
2478                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_control_is_listen_control),
2479                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_control_is_listen_control)
2480                 );
2481
2482         add_option (_("Solo / mute"), _solo_control_is_listen_control);
2483
2484         _listen_position = new ComboOption<ListenPosition> (
2485                 "listen-position",
2486                 _("Listen Position"),
2487                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_listen_position),
2488                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_listen_position)
2489                 );
2490
2491         _listen_position->add (AfterFaderListen, _("after-fader (AFL)"));
2492         _listen_position->add (PreFaderListen, _("pre-fader (PFL)"));
2493
2494         add_option (_("Solo / mute"), _listen_position);
2495
2496         ComboOption<PFLPosition>* pp = new ComboOption<PFLPosition> (
2497                 "pfl-position",
2498                 _("PFL signals come from"),
2499                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_pfl_position),
2500                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_pfl_position)
2501                 );
2502
2503         pp->add (PFLFromBeforeProcessors, _("before pre-fader processors"));
2504         pp->add (PFLFromAfterProcessors, _("pre-fader but after pre-fader processors"));
2505
2506         add_option (_("Solo / mute"), pp);
2507
2508         ComboOption<AFLPosition>* pa = new ComboOption<AFLPosition> (
2509                 "afl-position",
2510                 _("AFL signals come from"),
2511                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_afl_position),
2512                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_afl_position)
2513                 );
2514
2515         pa->add (AFLFromBeforeProcessors, _("immediately post-fader"));
2516         pa->add (AFLFromAfterProcessors, _("after post-fader processors (before pan)"));
2517
2518         add_option (_("Solo / mute"), pa);
2519
2520         parameter_changed ("use-monitor-bus");
2521
2522         add_option (_("Solo / mute"),
2523              new BoolOption (
2524                      "exclusive-solo",
2525                      _("Exclusive solo"),
2526                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_exclusive_solo),
2527                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_exclusive_solo)
2528                      ));
2529
2530         add_option (_("Solo / mute"),
2531              new BoolOption (
2532                      "show-solo-mutes",
2533                      _("Show solo muting"),
2534                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_show_solo_mutes),
2535                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_solo_mutes)
2536                      ));
2537
2538         add_option (_("Solo / mute"),
2539              new BoolOption (
2540                      "solo-mute-override",
2541                      _("Soloing overrides muting"),
2542                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_override),
2543                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_override)
2544                      ));
2545
2546         add_option (_("Solo / mute"), new OptionEditorHeading (_("Default track / bus muting options")));
2547
2548         add_option (_("Solo / mute"),
2549              new BoolOption (
2550                      "mute-affects-pre-fader",
2551                      _("Mute affects pre-fader sends"),
2552                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_pre_fader),
2553                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_pre_fader)
2554                      ));
2555
2556         add_option (_("Solo / mute"),
2557              new BoolOption (
2558                      "mute-affects-post-fader",
2559                      _("Mute affects post-fader sends"),
2560                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_post_fader),
2561                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_post_fader)
2562                      ));
2563
2564         add_option (_("Solo / mute"),
2565              new BoolOption (
2566                      "mute-affects-control-outs",
2567                      _("Mute affects control outputs"),
2568                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_control_outs),
2569                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_control_outs)
2570                      ));
2571
2572         add_option (_("Solo / mute"),
2573              new BoolOption (
2574                      "mute-affects-main-outs",
2575                      _("Mute affects main outputs"),
2576                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_main_outs),
2577                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_main_outs)
2578                      ));
2579
2580         add_option (_("Solo / mute"), new OptionEditorHeading (_("Send Routing")));
2581
2582         add_option (_("Solo / mute"),
2583              new BoolOption (
2584                      "link-send-and-route-panner",
2585                      _("Link panners of Aux and External Sends with main panner by default"),
2586                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_link_send_and_route_panner),
2587                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_link_send_and_route_panner)
2588                      ));
2589
2590         add_option (_("MIDI"),
2591                     new SpinOption<float> (
2592                             "midi-readahead",
2593                             _("MIDI read-ahead time (seconds)"),
2594                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_readahead),
2595                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_readahead),
2596                             0.1, 10, 0.1, 1,
2597                             "", 1.0, 1
2598                             ));
2599
2600         add_option (_("MIDI"),
2601                     new BoolOption (
2602                             "send-midi-clock",
2603                             _("Send MIDI Clock"),
2604                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_midi_clock),
2605                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_midi_clock)
2606                             ));
2607
2608         add_option (_("MIDI"),
2609                     new BoolOption (
2610                             "send-mtc",
2611                             _("Send MIDI Time Code"),
2612                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mtc),
2613                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mtc)
2614                             ));
2615
2616         add_option (_("MIDI"),
2617                     new SpinOption<int> (
2618                             "mtc-qf-speed-tolerance",
2619                             _("Percentage either side of normal transport speed to transmit MTC"),
2620                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mtc_qf_speed_tolerance),
2621                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mtc_qf_speed_tolerance),
2622                             0, 20, 1, 5
2623                             ));
2624
2625         add_option (_("MIDI"),
2626                     new BoolOption (
2627                             "mmc-control",
2628                             _("Obey MIDI Machine Control commands"),
2629                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_control),
2630                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_control)
2631                             ));
2632
2633         add_option (_("MIDI"),
2634                     new BoolOption (
2635                             "send-mmc",
2636                             _("Send MIDI Machine Control commands"),
2637                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mmc),
2638                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mmc)
2639                             ));
2640
2641         add_option (_("MIDI"),
2642                     new BoolOption (
2643                             "midi-feedback",
2644                             _("Send MIDI control feedback"),
2645                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_feedback),
2646                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_feedback)
2647                             ));
2648
2649         add_option (_("MIDI"),
2650              new SpinOption<uint8_t> (
2651                      "mmc-receive-device-id",
2652                      _("Inbound MMC device ID"),
2653                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_receive_device_id),
2654                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_receive_device_id),
2655                      0, 128, 1, 10
2656                      ));
2657
2658         add_option (_("MIDI"),
2659              new SpinOption<uint8_t> (
2660                      "mmc-send-device-id",
2661                      _("Outbound MMC device ID"),
2662                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_send_device_id),
2663                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_send_device_id),
2664                      0, 128, 1, 10
2665                      ));
2666
2667         add_option (_("MIDI"),
2668              new SpinOption<int32_t> (
2669                      "initial-program-change",
2670                      _("Initial program change"),
2671                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_initial_program_change),
2672                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_initial_program_change),
2673                      -1, 65536, 1, 10
2674                      ));
2675
2676         add_option (_("MIDI"),
2677                     new BoolOption (
2678                             "display-first-midi-bank-as-zero",
2679                             _("Display first MIDI bank/program as 0"),
2680                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_first_midi_bank_is_zero),
2681                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_first_midi_bank_is_zero)
2682                             ));
2683
2684         add_option (_("MIDI"),
2685              new BoolOption (
2686                      "never-display-periodic-midi",
2687                      _("Never display periodic MIDI messages (MTC, MIDI Clock)"),
2688                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_never_display_periodic_midi),
2689                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_never_display_periodic_midi)
2690                      ));
2691
2692         add_option (_("MIDI"),
2693              new BoolOption (
2694                      "sound-midi-notes",
2695                      _("Sound MIDI notes as they are selected"),
2696                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_sound_midi_notes),
2697                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_sound_midi_notes)
2698                      ));
2699
2700         add_option (_("MIDI"), new OptionEditorHeading (_("Midi Audition")));
2701
2702         ComboOption<std::string>* audition_synth = new ComboOption<std::string> (
2703                 "midi-audition-synth-uri",
2704                 _("Midi Audition Synth (LV2)"),
2705                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_audition_synth_uri),
2706                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_audition_synth_uri)
2707                 );
2708
2709         audition_synth->add(X_(""), _("None"));
2710         PluginInfoList all_plugs;
2711         PluginManager& manager (PluginManager::instance());
2712 #ifdef LV2_SUPPORT
2713         all_plugs.insert (all_plugs.end(), manager.lv2_plugin_info().begin(), manager.lv2_plugin_info().end());
2714
2715         for (PluginInfoList::const_iterator i = all_plugs.begin(); i != all_plugs.end(); ++i) {
2716                 if (manager.get_status (*i) == PluginManager::Hidden) continue;
2717                 if (!(*i)->is_instrument()) continue;
2718                 if ((*i)->type != ARDOUR::LV2) continue;
2719                 audition_synth->add((*i)->unique_id, (*i)->name);
2720         }
2721 #endif
2722
2723         add_option (_("MIDI"), audition_synth);
2724
2725         /* USER INTERACTION */
2726
2727         if (
2728 #ifdef PLATFORM_WINDOWS
2729                         true
2730 #else
2731                         getenv ("ARDOUR_BUNDLED")
2732 #endif
2733            )
2734         {
2735                 add_option (_("User interaction"), 
2736                             new BoolOption (
2737                                     "enable-translation",
2738                                     string_compose (_("Use translations of %1 messages\n"
2739                                                       "   <i>(requires a restart of %1 to take effect)</i>\n"
2740                                                       "   <i>(if available for your language preferences)</i>"), PROGRAM_NAME),
2741                                     sigc::ptr_fun (ARDOUR::translations_are_enabled),
2742                                     sigc::ptr_fun (ARDOUR::set_translations_enabled)));
2743         }
2744
2745         add_option (_("User interaction"), new OptionEditorHeading (_("Keyboard")));
2746
2747         add_option (_("User interaction"), new KeyboardOptions);
2748
2749         /* Control Surfaces */
2750
2751         add_option (_("Control Surfaces"), new ControlSurfacesOptions (*this));
2752
2753         ComboOption<RemoteModel>* rm = new ComboOption<RemoteModel> (
2754                 "remote-model",
2755                 _("Control surface remote ID"),
2756                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_remote_model),
2757                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_remote_model)
2758                 );
2759
2760         rm->add (UserOrdered, _("assigned by user"));
2761         rm->add (MixerOrdered, _("follows order of mixer"));
2762
2763         add_option (_("Control Surfaces"), rm);
2764
2765         /* VIDEO Timeline */
2766         add_option (_("Video"), new VideoTimelineOptions (_rc_config));
2767
2768 #if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined AUDIOUNIT_SUPPORT)
2769         /* Plugin options (currrently VST only) */
2770         add_option (_("Plugins"), new PluginOptions (_rc_config));
2771 #endif
2772
2773         /* INTERFACE */
2774
2775 #ifdef OPTIONAL_CAIRO_IMAGE_SURFACE
2776         BoolOption* bgc = new BoolOption (
2777                 "cairo-image-surface",
2778                 _("Disable Graphics Hardware Acceleration (requires restart)"),
2779                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_cairo_image_surface),
2780                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_cairo_image_surface)
2781                 );
2782
2783         Gtkmm2ext::UI::instance()->set_tip (bgc->tip_widget(), string_compose (
2784                                 _("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));
2785         add_option (S_("Preferences|GUI"), bgc);
2786 #endif
2787
2788 #ifdef CAIRO_SUPPORTS_FORCE_BUGGY_GRADIENTS_ENVIRONMENT_VARIABLE
2789         BoolOption* bgo = new BoolOption (
2790                 "buggy-gradients",
2791                 _("Possibly improve slow graphical performance (requires restart)"),
2792                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_buggy_gradients),
2793                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_buggy_gradients)
2794                 );
2795
2796         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));
2797         add_option (S_("Preferences|GUI"), bgo);
2798 #endif
2799
2800         add_option (S_("Preferences|GUI"),
2801              new BoolOption (
2802                      "widget-prelight",
2803                      _("Graphically indicate mouse pointer hovering over various widgets"),
2804                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_widget_prelight),
2805                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_widget_prelight)
2806                      ));
2807
2808 #ifdef TOOLTIPS_GOT_FIXED
2809         add_option (S_("Preferences|GUI"),
2810              new BoolOption (
2811                      "use-tooltips",
2812                      _("Show tooltips if mouse hovers over a control"),
2813                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_use_tooltips),
2814                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_use_tooltips)
2815                      ));
2816 #endif
2817
2818         add_option (S_("Preferences|GUI"),
2819              new BoolOption (
2820                      "show-name-highlight",
2821                      _("Use name highlight bars in region displays (requires a restart)"),
2822                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_show_name_highlight),
2823                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_show_name_highlight)
2824                      ));
2825
2826 #ifndef GTKOSX
2827         /* font scaling does nothing with GDK/Quartz */
2828         add_option (S_("Preferences|GUI"), new FontScalingOptions ());
2829 #endif
2830
2831         add_option (S_("GUI"),
2832                     new BoolOption (
2833                             "super-rapid-clock-update",
2834                             _("update transport clock display at FPS instead of every 100ms"),
2835                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_super_rapid_clock_update),
2836                             sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_super_rapid_clock_update)
2837                             ));
2838
2839
2840         /* Image cache size */
2841
2842         Gtk::Adjustment *ics = manage (new Gtk::Adjustment(0, 1, 1024, 10)); /* 1 MB to 1GB in steps of 10MB */
2843         HSliderOption *sics = new HSliderOption("waveform-cache-size",
2844                                                 _("Waveform image cache size (megabytes)"),
2845                                                 ics,
2846                                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_waveform_cache_size),
2847                                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_waveform_cache_size)
2848                         );
2849         sics->scale().set_digits (0);
2850         Gtkmm2ext::UI::instance()->set_tip
2851                 (sics->tip_widget(),
2852                  _("Increasing the cache size uses more memory to store waveform images, which can improve graphical performance."));
2853         add_option (S_("Preferences|GUI"), sics);
2854         
2855         /* Lock GUI timeout */
2856
2857         Gtk::Adjustment *lts = manage (new Gtk::Adjustment(0, 0, 1000, 1, 10));
2858         HSliderOption *slts = new HSliderOption("lock-gui-after-seconds",
2859                                                 _("Lock timeout (seconds)"),
2860                                                 lts,
2861                                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_lock_gui_after_seconds),
2862                                                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_lock_gui_after_seconds)
2863                         );
2864         slts->scale().set_digits (0);
2865         Gtkmm2ext::UI::instance()->set_tip
2866                 (slts->tip_widget(),
2867                  _("Lock GUI after this many idle seconds (zero to never lock)"));
2868         add_option (S_("Preferences|GUI"), slts);
2869
2870         /* The names of these controls must be the same as those given in MixerStrip
2871            for the actual widgets being controlled.
2872         */
2873         _mixer_strip_visibility.add (0, X_("Input"), _("Input"));
2874         _mixer_strip_visibility.add (0, X_("PhaseInvert"), _("Phase Invert"));
2875         _mixer_strip_visibility.add (0, X_("RecMon"), _("Record & Monitor"));
2876         _mixer_strip_visibility.add (0, X_("SoloIsoLock"), _("Solo Iso / Lock"));
2877         _mixer_strip_visibility.add (0, X_("Output"), _("Output"));
2878         _mixer_strip_visibility.add (0, X_("Comments"), _("Comments"));
2879         
2880         add_option (
2881                 S_("Preferences|GUI"),
2882                 new VisibilityOption (
2883                         _("Mixer Strip"),
2884                         &_mixer_strip_visibility,
2885                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_mixer_strip_visibility),
2886                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_mixer_strip_visibility)
2887                         )
2888                 );
2889
2890         add_option (S_("Preferences|GUI"),
2891              new BoolOption (
2892                      "default-narrow_ms",
2893                      _("Use narrow strips in the mixer by default"),
2894                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_default_narrow_ms),
2895                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_default_narrow_ms)
2896                      ));
2897
2898         add_option (S_("Preferences|Metering"), new OptionEditorHeading (_("Metering")));
2899
2900         ComboOption<float>* mht = new ComboOption<float> (
2901                 "meter-hold",
2902                 _("Peak hold time"),
2903                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_hold),
2904                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_hold)
2905                 );
2906
2907         mht->add (MeterHoldOff, _("off"));
2908         mht->add (MeterHoldShort, _("short"));
2909         mht->add (MeterHoldMedium, _("medium"));
2910         mht->add (MeterHoldLong, _("long"));
2911
2912         add_option (S_("Preferences|Metering"), mht);
2913
2914         ComboOption<float>* mfo = new ComboOption<float> (
2915                 "meter-falloff",
2916                 _("DPM fall-off"),
2917                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_falloff),
2918                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_falloff)
2919                 );
2920
2921         mfo->add (METER_FALLOFF_OFF,      _("off"));
2922         mfo->add (METER_FALLOFF_SLOWEST,  _("slowest [6.6dB/sec]"));
2923         mfo->add (METER_FALLOFF_SLOW,     _("slow [8.6dB/sec] (BBC PPM, EBU PPM)"));
2924         mfo->add (METER_FALLOFF_SLOWISH,  _("moderate [12.0dB/sec] (DIN)"));
2925         mfo->add (METER_FALLOFF_MODERATE, _("medium [13.3dB/sec] (EBU Digi PPM, IRT Digi PPM)"));
2926         mfo->add (METER_FALLOFF_MEDIUM,   _("fast [20dB/sec]"));
2927         mfo->add (METER_FALLOFF_FAST,     _("very fast [32dB/sec]"));
2928
2929         add_option (S_("Preferences|Metering"), mfo);
2930
2931         ComboOption<MeterLineUp>* mlu = new ComboOption<MeterLineUp> (
2932                 "meter-line-up-level",
2933                 _("Meter line-up level; 0dBu"),
2934                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_line_up_level),
2935                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_line_up_level)
2936                 );
2937
2938         mlu->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
2939         mlu->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
2940         mlu->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
2941         mlu->add (MeteringLineUp15, _("-15dBFS (DIN)"));
2942
2943         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."));
2944
2945         add_option (S_("Preferences|Metering"), mlu);
2946
2947         ComboOption<MeterLineUp>* mld = new ComboOption<MeterLineUp> (
2948                 "meter-line-up-din",
2949                 _("IEC1/DIN Meter line-up level; 0dBu"),
2950                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_line_up_din),
2951                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_line_up_din)
2952                 );
2953
2954         mld->add (MeteringLineUp24, _("-24dBFS (SMPTE US: 4dBu = -20dBFS)"));
2955         mld->add (MeteringLineUp20, _("-20dBFS (SMPTE RP.0155)"));
2956         mld->add (MeteringLineUp18, _("-18dBFS (EBU, BBC)"));
2957         mld->add (MeteringLineUp15, _("-15dBFS (DIN)"));
2958
2959         Gtkmm2ext::UI::instance()->set_tip (mld->tip_widget(), _("Reference level for IEC1/DIN meter."));
2960
2961         add_option (S_("Preferences|Metering"), mld);
2962
2963         ComboOption<VUMeterStandard>* mvu = new ComboOption<VUMeterStandard> (
2964                 "meter-vu-standard",
2965                 _("VU Meter standard"),
2966                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_vu_standard),
2967                 sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_vu_standard)
2968                 );
2969
2970         mvu->add (MeteringVUfrench,   _("0VU = -2dBu (France)"));
2971         mvu->add (MeteringVUamerican, _("0VU = 0dBu (North America, Australia)"));
2972         mvu->add (MeteringVUstandard, _("0VU = +4dBu (standard)"));
2973         mvu->add (MeteringVUeight,    _("0VU = +8dBu"));
2974
2975         add_option (S_("Preferences|Metering"), mvu);
2976
2977         Gtk::Adjustment *mpk = manage (new Gtk::Adjustment(0, -10, 0, .1, .1));
2978         HSliderOption *mpks = new HSliderOption("meter-peak",
2979                         _("Peak threshold [dBFS]"),
2980                         mpk,
2981                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_peak),
2982                         sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_peak)
2983                         );
2984
2985
2986         ComboOption<MeterType>* mtm = new ComboOption<MeterType> (
2987                 "meter-type-master",
2988                 _("Default Meter Type for Master Bus"),
2989                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_master),
2990                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_master)
2991                 );
2992         mtm->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
2993         mtm->add (MeterK20,     ArdourMeter::meter_type_string(MeterK20));
2994         mtm->add (MeterK14,     ArdourMeter::meter_type_string(MeterK14));
2995         mtm->add (MeterK12,     ArdourMeter::meter_type_string(MeterK12));
2996         mtm->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
2997         mtm->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
2998         mtm->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
2999         mtm->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
3000
3001         add_option (S_("Preferences|Metering"), mtm);
3002
3003
3004         ComboOption<MeterType>* mtb = new ComboOption<MeterType> (
3005                 "meter-type-bus",
3006                 _("Default Meter Type for Busses"),
3007                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_bus),
3008                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_bus)
3009                 );
3010         mtb->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
3011         mtb->add (MeterK20,     ArdourMeter::meter_type_string(MeterK20));
3012         mtb->add (MeterK14,     ArdourMeter::meter_type_string(MeterK14));
3013         mtb->add (MeterK12,     ArdourMeter::meter_type_string(MeterK12));
3014         mtb->add (MeterIEC1DIN, ArdourMeter::meter_type_string(MeterIEC1DIN));
3015         mtb->add (MeterIEC1NOR, ArdourMeter::meter_type_string(MeterIEC1NOR));
3016         mtb->add (MeterIEC2BBC, ArdourMeter::meter_type_string(MeterIEC2BBC));
3017         mtb->add (MeterIEC2EBU, ArdourMeter::meter_type_string(MeterIEC2EBU));
3018
3019         add_option (S_("Preferences|Metering"), mtb);
3020
3021         ComboOption<MeterType>* mtt = new ComboOption<MeterType> (
3022                 "meter-type-track",
3023                 _("Default Meter Type for Tracks"),
3024                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_type_track),
3025                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_type_track)
3026                 );
3027         mtt->add (MeterPeak,    ArdourMeter::meter_type_string(MeterPeak));
3028         mtt->add (MeterPeak0dB, ArdourMeter::meter_type_string(MeterPeak0dB));
3029
3030         add_option (S_("Preferences|Metering"), mtt);
3031
3032
3033         Gtkmm2ext::UI::instance()->set_tip
3034                 (mpks->tip_widget(),
3035                  _("Specify the audio signal level in dbFS at and above which the meter-peak indicator will flash red."));
3036
3037         add_option (S_("Preferences|Metering"), mpks);
3038
3039         add_option (S_("Preferences|Metering"),
3040              new BoolOption (
3041                      "meter-style-led",
3042                      _("LED meter style"),
3043                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::get_meter_style_led),
3044                      sigc::mem_fun (UIConfiguration::instance(), &UIConfiguration::set_meter_style_led)
3045                      ));
3046
3047         /* and now the theme manager */
3048
3049         ThemeManager* tm = manage (new ThemeManager);
3050         add_page (_("Theme"), *tm);
3051 }
3052
3053 void
3054 RCOptionEditor::parameter_changed (string const & p)
3055 {
3056         OptionEditor::parameter_changed (p);
3057
3058         if (p == "use-monitor-bus") {
3059                 bool const s = Config->get_use_monitor_bus ();
3060                 if (!s) {
3061                         /* we can't use this if we don't have a monitor bus */
3062                         Config->set_solo_control_is_listen_control (false);
3063                 }
3064                 _solo_control_is_listen_control->set_sensitive (s);
3065                 _listen_position->set_sensitive (s);
3066         } else if (p == "sync-source") {
3067                 _sync_source->set_sensitive (true);
3068                 if (_session) {
3069                         _sync_source->set_sensitive (!_session->config.get_external_sync());
3070                 }
3071                 switch(Config->get_sync_source()) {
3072                 case ARDOUR::MTC:
3073                 case ARDOUR::LTC:
3074                         _sync_genlock->set_sensitive (true);
3075                         _sync_framerate->set_sensitive (true);
3076                         _sync_source_2997->set_sensitive (true);
3077                         break;
3078                 default:
3079                         _sync_genlock->set_sensitive (false);
3080                         _sync_framerate->set_sensitive (false);
3081                         _sync_source_2997->set_sensitive (false);
3082                         break;
3083                 }
3084         } else if (p == "send-ltc") {
3085                 bool const s = Config->get_send_ltc ();
3086                 _ltc_send_continuously->set_sensitive (s);
3087                 _ltc_volume_slider->set_sensitive (s);
3088         }
3089 }
3090
3091 void RCOptionEditor::ltc_generator_volume_changed () {
3092         _rc_config->set_ltc_output_volume (pow(10, _ltc_volume_adjustment->get_value() / 20));
3093 }
3094
3095 void
3096 RCOptionEditor::populate_sync_options ()
3097 {
3098         vector<SyncSource> sync_opts = ARDOUR::get_available_sync_options ();
3099
3100         _sync_source->clear ();
3101
3102         for (vector<SyncSource>::iterator i = sync_opts.begin(); i != sync_opts.end(); ++i) {
3103                 _sync_source->add (*i, sync_source_to_string (*i));
3104         }
3105
3106         if (sync_opts.empty()) {
3107                 _sync_source->set_sensitive(false);
3108         } else {
3109                 if (std::find(sync_opts.begin(), sync_opts.end(), _rc_config->get_sync_source()) == sync_opts.end()) {
3110                         _rc_config->set_sync_source(sync_opts.front());
3111                 }
3112         }
3113 }