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