Setup fixed ports for MIDI control data; hence remove configuration of those ports...
[ardour.git] / gtk2_ardour / rc_option_editor.cc
1 #include <gtkmm/liststore.h>
2 #include <gtkmm/stock.h>
3 #include <gtkmm/scale.h>
4 #include <gtkmm2ext/utils.h>
5 #include <gtkmm2ext/slider_controller.h>
6
7 #include "pbd/fpu.h"
8 #include "pbd/cpus.h"
9
10 #include "midi++/manager.h"
11
12 #include "ardour/audioengine.h"
13 #include "ardour/dB.h"
14 #include "ardour/rc_configuration.h"
15 #include "ardour/control_protocol_manager.h"
16 #include "control_protocol/control_protocol.h"
17
18 #include "gui_thread.h"
19 #include "midi_tracer.h"
20 #include "rc_option_editor.h"
21 #include "utils.h"
22 #include "midi_port_dialog.h"
23 #include "sfdb_ui.h"
24 #include "keyboard.h"
25 #include "i18n.h"
26
27 using namespace std;
28 using namespace Gtk;
29 using namespace Gtkmm2ext;
30 using namespace PBD;
31 using namespace ARDOUR;
32
33 class ClickOptions : public OptionEditorBox
34 {
35 public:
36         ClickOptions (RCConfiguration* c, ArdourDialog* p)
37                 : _rc_config (c),
38                   _parent (p)
39         {
40                 Table* t = manage (new Table (2, 3));
41                 t->set_spacings (4);
42
43                 Label* l = manage (new Label (_("Click audio file:")));
44                 l->set_alignment (0, 0.5);
45                 t->attach (*l, 0, 1, 0, 1, FILL);
46                 t->attach (_click_path_entry, 1, 2, 0, 1, FILL);
47                 Button* b = manage (new Button (_("Browse...")));
48                 b->signal_clicked().connect (sigc::mem_fun (*this, &ClickOptions::click_browse_clicked));
49                 t->attach (*b, 2, 3, 0, 1, FILL);
50
51                 l = manage (new Label (_("Click emphasis audio file:")));
52                 l->set_alignment (0, 0.5);
53                 t->attach (*l, 0, 1, 1, 2, FILL);
54                 t->attach (_click_emphasis_path_entry, 1, 2, 1, 2, FILL);
55                 b = manage (new Button (_("Browse...")));
56                 b->signal_clicked().connect (sigc::mem_fun (*this, &ClickOptions::click_emphasis_browse_clicked));
57                 t->attach (*b, 2, 3, 1, 2, FILL);
58
59                 _box->pack_start (*t, false, false);
60         }
61
62         void parameter_changed (string const & p)
63         {
64                 if (p == "click-sound") {
65                         _click_path_entry.set_text (_rc_config->get_click_sound());
66                 } else if (p == "click-emphasis-sound") {
67                         _click_emphasis_path_entry.set_text (_rc_config->get_click_emphasis_sound());
68                 }
69         }
70
71         void set_state_from_config ()
72         {
73                 parameter_changed ("click-sound");
74                 parameter_changed ("click-emphasis-sound");
75         }
76
77 private:
78
79         void click_browse_clicked ()
80         {
81                 SoundFileChooser sfdb (*_parent, _("Choose Click"));
82
83                 sfdb.show_all ();
84                 sfdb.present ();
85
86                 if (sfdb.run () == RESPONSE_OK) {
87                         click_chosen (sfdb.get_filename());
88                 }
89         }
90
91         void click_chosen (string const & path)
92         {
93                 _click_path_entry.set_text (path);
94                 _rc_config->set_click_sound (path);
95         }
96
97         void click_emphasis_browse_clicked ()
98         {
99                 SoundFileChooser sfdb (*_parent, _("Choose Click Emphasis"));
100
101                 sfdb.show_all ();
102                 sfdb.present ();
103
104                 if (sfdb.run () == RESPONSE_OK) {
105                         click_emphasis_chosen (sfdb.get_filename());
106                 }
107         }
108
109         void click_emphasis_chosen (string const & path)
110         {
111                 _click_emphasis_path_entry.set_text (path);
112                 _rc_config->set_click_emphasis_sound (path);
113         }
114
115         RCConfiguration* _rc_config;
116         ArdourDialog* _parent;
117         Entry _click_path_entry;
118         Entry _click_emphasis_path_entry;
119 };
120
121 class UndoOptions : public OptionEditorBox
122 {
123 public:
124         UndoOptions (RCConfiguration* c) :
125                 _rc_config (c),
126                 _limit_undo_button (_("Limit undo history to")),
127                 _save_undo_button (_("Save undo history of"))
128         {
129                 Table* t = new Table (2, 3);
130                 t->set_spacings (4);
131
132                 t->attach (_limit_undo_button, 0, 1, 0, 1, FILL);
133                 _limit_undo_spin.set_range (0, 512);
134                 _limit_undo_spin.set_increments (1, 10);
135                 t->attach (_limit_undo_spin, 1, 2, 0, 1, FILL | EXPAND);
136                 Label* l = manage (new Label (_("commands")));
137                 l->set_alignment (0, 0.5);
138                 t->attach (*l, 2, 3, 0, 1);
139
140                 t->attach (_save_undo_button, 0, 1, 1, 2, FILL);
141                 _save_undo_spin.set_range (0, 512);
142                 _save_undo_spin.set_increments (1, 10);
143                 t->attach (_save_undo_spin, 1, 2, 1, 2, FILL | EXPAND);
144                 l = manage (new Label (_("commands")));
145                 l->set_alignment (0, 0.5);
146                 t->attach (*l, 2, 3, 1, 2);
147
148                 _box->pack_start (*t);
149
150                 _limit_undo_button.signal_toggled().connect (sigc::mem_fun (*this, &UndoOptions::limit_undo_toggled));
151                 _limit_undo_spin.signal_value_changed().connect (sigc::mem_fun (*this, &UndoOptions::limit_undo_changed));
152                 _save_undo_button.signal_toggled().connect (sigc::mem_fun (*this, &UndoOptions::save_undo_toggled));
153                 _save_undo_spin.signal_value_changed().connect (sigc::mem_fun (*this, &UndoOptions::save_undo_changed));
154         }
155
156         void parameter_changed (string const & p)
157         {
158                 if (p == "history-depth") {
159                         int32_t const d = _rc_config->get_history_depth();
160                         _limit_undo_button.set_active (d != 0);
161                         _limit_undo_spin.set_sensitive (d != 0);
162                         _limit_undo_spin.set_value (d);
163                 } else if (p == "save-history") {
164                         bool const x = _rc_config->get_save_history ();
165                         _save_undo_button.set_active (x);
166                         _save_undo_spin.set_sensitive (x);
167                 } else if (p == "save-history-depth") {
168                         _save_undo_spin.set_value (_rc_config->get_saved_history_depth());
169                 }
170         }
171
172         void set_state_from_config ()
173         {
174                 parameter_changed ("save-history");
175                 parameter_changed ("history-depth");
176                 parameter_changed ("save-history-depth");
177         }
178
179         void limit_undo_toggled ()
180         {
181                 bool const x = _limit_undo_button.get_active ();
182                 _limit_undo_spin.set_sensitive (x);
183                 int32_t const n = x ? 16 : 0;
184                 _limit_undo_spin.set_value (n);
185                 _rc_config->set_history_depth (n);
186         }
187
188         void limit_undo_changed ()
189         {
190                 _rc_config->set_history_depth (_limit_undo_spin.get_value_as_int ());
191         }
192
193         void save_undo_toggled ()
194         {
195                 bool const x = _save_undo_button.get_active ();
196                 _rc_config->set_save_history (x);
197         }
198
199         void save_undo_changed ()
200         {
201                 _rc_config->set_saved_history_depth (_save_undo_spin.get_value_as_int ());
202         }
203
204 private:
205         RCConfiguration* _rc_config;
206         CheckButton _limit_undo_button;
207         SpinButton _limit_undo_spin;
208         CheckButton _save_undo_button;
209         SpinButton _save_undo_spin;
210 };
211
212
213
214 static const struct {
215     const char *name;
216     guint modifier;
217 } modifiers[] = {
218
219         { "Unmodified", 0 },
220
221 #ifdef GTKOSX
222
223         /* Command = Meta
224            Option/Alt = Mod1
225         */
226         { "Shift", GDK_SHIFT_MASK },
227         { "Command", GDK_META_MASK },
228         { "Control", GDK_CONTROL_MASK },
229         { "Option", GDK_MOD1_MASK },
230         { "Command-Shift", GDK_META_MASK|GDK_SHIFT_MASK },
231         { "Command-Option", GDK_MOD1_MASK|GDK_META_MASK },
232         { "Shift-Option", GDK_SHIFT_MASK|GDK_MOD1_MASK },
233         { "Shift-Command-Option", GDK_MOD5_MASK|GDK_SHIFT_MASK|GDK_META_MASK },
234
235 #else
236         { "Shift", GDK_SHIFT_MASK },
237         { "Control", GDK_CONTROL_MASK },
238         { "Alt (Mod1)", GDK_MOD1_MASK },
239         { "Control-Shift", GDK_CONTROL_MASK|GDK_SHIFT_MASK },
240         { "Control-Alt", GDK_CONTROL_MASK|GDK_MOD1_MASK },
241         { "Shift-Alt", GDK_SHIFT_MASK|GDK_MOD1_MASK },
242         { "Control-Shift-Alt", GDK_CONTROL_MASK|GDK_SHIFT_MASK|GDK_MOD1_MASK },
243         { "Mod2", GDK_MOD2_MASK },
244         { "Mod3", GDK_MOD3_MASK },
245         { "Mod4", GDK_MOD4_MASK },
246         { "Mod5", GDK_MOD5_MASK },
247 #endif
248         { 0, 0 }
249 };
250
251
252 class KeyboardOptions : public OptionEditorBox
253 {
254 public:
255         KeyboardOptions () :
256                   _delete_button_adjustment (3, 1, 12),
257                   _delete_button_spin (_delete_button_adjustment),
258                   _edit_button_adjustment (3, 1, 5),
259                   _edit_button_spin (_edit_button_adjustment)
260
261         {
262                 /* internationalize and prepare for use with combos */
263
264                 vector<string> dumb;
265                 for (int i = 0; modifiers[i].name; ++i) {
266                         dumb.push_back (_(modifiers[i].name));
267                 }
268
269                 set_popdown_strings (_edit_modifier_combo, dumb);
270                 _edit_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::edit_modifier_chosen));
271
272                 for (int x = 0; modifiers[x].name; ++x) {
273                         if (modifiers[x].modifier == Keyboard::edit_modifier ()) {
274                                 _edit_modifier_combo.set_active_text (_(modifiers[x].name));
275                                 break;
276                         }
277                 }
278
279                 Table* t = manage (new Table (4, 4));
280                 t->set_spacings (4);
281
282                 Label* l = manage (new Label (_("Edit using:")));
283                 l->set_name ("OptionsLabel");
284                 l->set_alignment (0, 0.5);
285
286                 t->attach (*l, 0, 1, 0, 1, FILL | EXPAND, FILL);
287                 t->attach (_edit_modifier_combo, 1, 2, 0, 1, FILL | EXPAND, FILL);
288
289                 l = manage (new Label (_("+ button")));
290                 l->set_name ("OptionsLabel");
291
292                 t->attach (*l, 3, 4, 0, 1, FILL | EXPAND, FILL);
293                 t->attach (_edit_button_spin, 4, 5, 0, 1, FILL | EXPAND, FILL);
294
295                 _edit_button_spin.set_name ("OptionsEntry");
296                 _edit_button_adjustment.set_value (Keyboard::edit_button());
297                 _edit_button_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::edit_button_changed));
298
299                 set_popdown_strings (_delete_modifier_combo, dumb);
300                 _delete_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::delete_modifier_chosen));
301
302                 for (int x = 0; modifiers[x].name; ++x) {
303                         if (modifiers[x].modifier == Keyboard::delete_modifier ()) {
304                                 _delete_modifier_combo.set_active_text (_(modifiers[x].name));
305                                 break;
306                         }
307                 }
308
309                 l = manage (new Label (_("Delete using:")));
310                 l->set_name ("OptionsLabel");
311                 l->set_alignment (0, 0.5);
312
313                 t->attach (*l, 0, 1, 1, 2, FILL | EXPAND, FILL);
314                 t->attach (_delete_modifier_combo, 1, 2, 1, 2, FILL | EXPAND, FILL);
315
316                 l = manage (new Label (_("+ button")));
317                 l->set_name ("OptionsLabel");
318
319                 t->attach (*l, 3, 4, 1, 2, FILL | EXPAND, FILL);
320                 t->attach (_delete_button_spin, 4, 5, 1, 2, FILL | EXPAND, FILL);
321
322                 _delete_button_spin.set_name ("OptionsEntry");
323                 _delete_button_adjustment.set_value (Keyboard::delete_button());
324                 _delete_button_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::delete_button_changed));
325
326                 set_popdown_strings (_snap_modifier_combo, dumb);
327                 _snap_modifier_combo.signal_changed().connect (sigc::mem_fun(*this, &KeyboardOptions::snap_modifier_chosen));
328
329                 for (int x = 0; modifiers[x].name; ++x) {
330                         if (modifiers[x].modifier == (guint) Keyboard::snap_modifier ()) {
331                                 _snap_modifier_combo.set_active_text (_(modifiers[x].name));
332                                 break;
333                         }
334                 }
335
336                 l = manage (new Label (_("Toggle snap using:")));
337                 l->set_name ("OptionsLabel");
338                 l->set_alignment (0, 0.5);
339
340                 t->attach (*l, 0, 1, 2, 3, FILL | EXPAND, FILL);
341                 t->attach (_snap_modifier_combo, 1, 2, 2, 3, FILL | EXPAND, FILL);
342
343                 vector<string> strs;
344
345                 for (map<string,string>::iterator bf = Keyboard::binding_files.begin(); bf != Keyboard::binding_files.end(); ++bf) {
346                         strs.push_back (bf->first);
347                 }
348
349                 set_popdown_strings (_keyboard_layout_selector, strs);
350                 _keyboard_layout_selector.set_active_text (Keyboard::current_binding_name());
351                 _keyboard_layout_selector.signal_changed().connect (sigc::mem_fun (*this, &KeyboardOptions::bindings_changed));
352
353                 l = manage (new Label (_("Keyboard layout:")));
354                 l->set_name ("OptionsLabel");
355                 l->set_alignment (0, 0.5);
356
357                 t->attach (*l, 0, 1, 3, 4, FILL | EXPAND, FILL);
358                 t->attach (_keyboard_layout_selector, 1, 2, 3, 4, FILL | EXPAND, FILL);
359
360                 _box->pack_start (*t, false, false);
361         }
362
363         void parameter_changed (string const &)
364         {
365                 /* XXX: these aren't really config options... */
366         }
367
368         void set_state_from_config ()
369         {
370                 /* XXX: these aren't really config options... */
371         }
372
373 private:
374
375         void bindings_changed ()
376         {
377                 string const txt = _keyboard_layout_selector.get_active_text();
378
379                 /* XXX: config...?  for all this keyboard stuff */
380
381                 for (map<string,string>::iterator i = Keyboard::binding_files.begin(); i != Keyboard::binding_files.end(); ++i) {
382                         if (txt == i->first) {
383                                 if (Keyboard::load_keybindings (i->second)) {
384                                         Keyboard::save_keybindings ();
385                                 }
386                         }
387                 }
388         }
389
390         void edit_modifier_chosen ()
391         {
392                 string const txt = _edit_modifier_combo.get_active_text();
393
394                 for (int i = 0; modifiers[i].name; ++i) {
395                         if (txt == _(modifiers[i].name)) {
396                                 Keyboard::set_edit_modifier (modifiers[i].modifier);
397                                 break;
398                         }
399                 }
400         }
401
402         void delete_modifier_chosen ()
403         {
404                 string const txt = _delete_modifier_combo.get_active_text();
405
406                 for (int i = 0; modifiers[i].name; ++i) {
407                         if (txt == _(modifiers[i].name)) {
408                                 Keyboard::set_delete_modifier (modifiers[i].modifier);
409                                 break;
410                         }
411                 }
412         }
413
414         void snap_modifier_chosen ()
415         {
416                 string const txt = _snap_modifier_combo.get_active_text();
417
418                 for (int i = 0; modifiers[i].name; ++i) {
419                         if (txt == _(modifiers[i].name)) {
420                                 Keyboard::set_snap_modifier (modifiers[i].modifier);
421                                 break;
422                         }
423                 }
424         }
425
426         void delete_button_changed ()
427         {
428                 Keyboard::set_delete_button (_delete_button_spin.get_value_as_int());
429         }
430
431         void edit_button_changed ()
432         {
433                 Keyboard::set_edit_button (_edit_button_spin.get_value_as_int());
434         }
435
436         ComboBoxText _keyboard_layout_selector;
437         ComboBoxText _edit_modifier_combo;
438         ComboBoxText _delete_modifier_combo;
439         ComboBoxText _snap_modifier_combo;
440         Adjustment _delete_button_adjustment;
441         SpinButton _delete_button_spin;
442         Adjustment _edit_button_adjustment;
443         SpinButton _edit_button_spin;
444 };
445
446 class FontScalingOptions : public OptionEditorBox
447 {
448 public:
449         FontScalingOptions (RCConfiguration* c) :
450                 _rc_config (c),
451                 _dpi_adjustment (50, 50, 250, 1, 10),
452                 _dpi_slider (_dpi_adjustment)
453         {
454                 _dpi_adjustment.set_value (_rc_config->get_font_scale () / 1024);
455
456                 Label* l = manage (new Label (_("Font scaling:")));
457                 l->set_name ("OptionsLabel");
458
459                 _dpi_slider.set_update_policy (UPDATE_DISCONTINUOUS);
460                 HBox* h = manage (new HBox);
461                 h->set_spacing (4);
462                 h->pack_start (*l, false, false);
463                 h->pack_start (_dpi_slider, true, true);
464
465                 _box->pack_start (*h, false, false);
466
467                 _dpi_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &FontScalingOptions::dpi_changed));
468         }
469
470         void parameter_changed (string const & p)
471         {
472                 if (p == "font-scale") {
473                         _dpi_adjustment.set_value (_rc_config->get_font_scale() / 1024);
474                 }
475         }
476
477         void set_state_from_config ()
478         {
479                 parameter_changed ("font-scale");
480         }
481
482 private:
483
484         void dpi_changed ()
485         {
486                 _rc_config->set_font_scale ((long) floor (_dpi_adjustment.get_value() * 1024));
487                 /* XXX: should be triggered from the parameter changed signal */
488                 reset_dpi ();
489         }
490
491         RCConfiguration* _rc_config;
492         Adjustment _dpi_adjustment;
493         HScale _dpi_slider;
494 };
495
496 class BufferingOptions : public OptionEditorBox
497 {
498 public:
499         BufferingOptions (RCConfiguration* c) 
500                 : _rc_config (c)
501                 , _playback_adjustment (5, 1, 60, 1, 4)
502                 , _capture_adjustment (5, 1, 60, 1, 4)
503                 , _playback_slider (_playback_adjustment)
504                 , _capture_slider (_capture_adjustment)
505         {
506                 _playback_adjustment.set_value (_rc_config->get_audio_playback_buffer_seconds());
507
508                 Label* l = manage (new Label (_("Playback (seconds of buffering):")));
509                 l->set_name ("OptionsLabel");
510
511                 _playback_slider.set_update_policy (UPDATE_DISCONTINUOUS);
512                 HBox* h = manage (new HBox);
513                 h->set_spacing (4);
514                 h->pack_start (*l, false, false);
515                 h->pack_start (_playback_slider, true, true);
516
517                 _box->pack_start (*h, false, false);
518                 
519                 _capture_adjustment.set_value (_rc_config->get_audio_capture_buffer_seconds());
520
521                 l = manage (new Label (_("Recording (seconds of buffering):")));
522                 l->set_name ("OptionsLabel");
523
524                 _capture_slider.set_update_policy (UPDATE_DISCONTINUOUS);
525                 h = manage (new HBox);
526                 h->set_spacing (4);
527                 h->pack_start (*l, false, false);
528                 h->pack_start (_capture_slider, true, true);
529
530                 _box->pack_start (*h, false, false);
531                 
532                 _capture_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &BufferingOptions::capture_changed));
533                 _playback_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &BufferingOptions::playback_changed));
534         }
535
536         void parameter_changed (string const & p)
537         {
538                 if (p == "playback-buffer-seconds") {
539                         _playback_adjustment.set_value (_rc_config->get_audio_playback_buffer_seconds());
540                 } else if (p == "capture-buffer-seconds") {
541                         _capture_adjustment.set_value (_rc_config->get_audio_capture_buffer_seconds());
542                 }
543         }
544
545         void set_state_from_config ()
546         {
547                 parameter_changed ("playback-buffer-seconds");
548                 parameter_changed ("capture-buffer-seconds");
549         }
550
551 private:
552
553         void playback_changed ()
554         {
555                 _rc_config->set_audio_playback_buffer_seconds ((long) _playback_adjustment.get_value());
556         }
557
558         void capture_changed ()
559         {
560                 _rc_config->set_audio_capture_buffer_seconds ((long) _capture_adjustment.get_value());
561         }
562
563         RCConfiguration* _rc_config;
564         Adjustment _playback_adjustment;
565         Adjustment _capture_adjustment;
566         HScale _playback_slider;
567         HScale _capture_slider;
568 };
569
570 class ControlSurfacesOptions : public OptionEditorBox
571 {
572 public:
573         ControlSurfacesOptions (ArdourDialog& parent)
574                 : _parent (parent)
575         {
576                 _store = ListStore::create (_model);
577                 _view.set_model (_store);
578                 _view.append_column (_("Name"), _model.name);
579                 _view.get_column(0)->set_resizable (true);
580                 _view.get_column(0)->set_expand (true);
581                 _view.append_column_editable (_("Enabled"), _model.enabled);
582                 _view.append_column_editable (_("Feedback"), _model.feedback);
583
584                 _box->pack_start (_view, false, false);
585
586                 Label* label = manage (new Label);
587                 label->set_markup (string_compose (X_("<i>%1</i>"), _("Double-click on a name to edit settings for an enabled protocol")));
588
589                 _box->pack_start (*label, false, false);
590                 label->show ();
591                 
592                 _store->signal_row_changed().connect (sigc::mem_fun (*this, &ControlSurfacesOptions::model_changed));
593                 _view.signal_button_press_event().connect_notify (sigc::mem_fun(*this, &ControlSurfacesOptions::edit_clicked));
594         }
595
596         void parameter_changed (std::string const &)
597         {
598
599         }
600
601         void set_state_from_config ()
602         {
603                 _store->clear ();
604
605                 ControlProtocolManager& m = ControlProtocolManager::instance ();
606                 for (list<ControlProtocolInfo*>::iterator i = m.control_protocol_info.begin(); i != m.control_protocol_info.end(); ++i) {
607
608                         if (!(*i)->mandatory) {
609                                 TreeModel::Row r = *_store->append ();
610                                 r[_model.name] = (*i)->name;
611                                 r[_model.enabled] = ((*i)->protocol || (*i)->requested);
612                                 r[_model.feedback] = ((*i)->protocol && (*i)->protocol->get_feedback ());
613                                 r[_model.protocol_info] = *i;
614                         }
615                 }
616         }
617
618 private:
619
620         void model_changed (TreeModel::Path const &, TreeModel::iterator const & i)
621         {
622                 TreeModel::Row r = *i;
623
624                 ControlProtocolInfo* cpi = r[_model.protocol_info];
625                 if (!cpi) {
626                         return;
627                 }
628
629                 bool const was_enabled = (cpi->protocol != 0);
630                 bool const is_enabled = r[_model.enabled];
631
632                 if (was_enabled != is_enabled) {
633                         if (!was_enabled) {
634                                 ControlProtocolManager::instance().instantiate (*cpi);
635                         } else {
636                                 ControlProtocolManager::instance().teardown (*cpi);
637                         }
638                 }
639
640                 bool const was_feedback = (cpi->protocol && cpi->protocol->get_feedback ());
641                 bool const is_feedback = r[_model.feedback];
642
643                 if (was_feedback != is_feedback && cpi->protocol) {
644                         cpi->protocol->set_feedback (is_feedback);
645                 }
646         }
647
648         void edit_clicked (GdkEventButton* ev)
649         {
650                 if (ev->type != GDK_2BUTTON_PRESS) {
651                         return;
652                 }
653
654                 std::string name;
655                 ControlProtocolInfo* cpi;
656                 TreeModel::Row row;
657                 
658                 row = *(_view.get_selection()->get_selected());
659
660                 Window* win = row[_model.editor];
661                 if (win && !win->is_visible()) {
662                         win->present (); 
663                 } else {
664                         cpi = row[_model.protocol_info];
665                         
666                         if (cpi && cpi->protocol && cpi->protocol->has_editor ()) {
667                                 Box* box = (Box*) cpi->protocol->get_gui ();
668                                 if (box) {
669                                         string title = row[_model.name];
670                                         ArdourDialog* win = new ArdourDialog (_parent, title);
671                                         win->get_vbox()->pack_start (*box, false, false);
672                                         box->show ();
673                                         win->present ();
674                                         row[_model.editor] = win;
675                                 }
676                         }
677                 }
678         }
679
680         class ControlSurfacesModelColumns : public TreeModelColumnRecord
681         {
682         public:
683
684                 ControlSurfacesModelColumns ()
685                 {
686                         add (name);
687                         add (enabled);
688                         add (feedback);
689                         add (protocol_info);
690                         add (editor);
691                 }
692
693                 TreeModelColumn<string> name;
694                 TreeModelColumn<bool> enabled;
695                 TreeModelColumn<bool> feedback;
696                 TreeModelColumn<ControlProtocolInfo*> protocol_info;
697                 TreeModelColumn<Gtk::Window*> editor;
698         };
699
700         Glib::RefPtr<ListStore> _store;
701         ControlSurfacesModelColumns _model;
702         TreeView _view;
703         Gtk::Window& _parent;
704 };
705
706
707 RCOptionEditor::RCOptionEditor ()
708         : OptionEditor (Config, string_compose (_("%1 Preferences"), PROGRAM_NAME))
709         , _rc_config (Config)
710 {
711         /* MISC */
712
713         uint32_t hwcpus = hardware_concurrency ();
714
715         if (hwcpus > 1) {
716                 add_option (_("Misc"), new OptionEditorHeading (_("DSP CPU Utilization")));
717                 
718                 ComboOption<uint32_t>* procs = new ComboOption<uint32_t> (
719                         "processor-usage",
720                         _("Signal processing uses: "),
721                         sigc::mem_fun (*_rc_config, &RCConfiguration::get_processor_usage),
722                         sigc::mem_fun (*_rc_config, &RCConfiguration::set_processor_usage)
723                         );
724                 
725                 procs->add (-1, _("All but one"));
726                 procs->add (0, _("All available processors"));
727                 
728                 for (uint32_t i = 2; i < hwcpus; ++i) {
729                         procs->add (1, string_compose (_("%1 processors"), i));
730                 }
731                 
732                 add_option (_("Misc"), procs);
733         }
734
735         add_option (_("Misc"), new OptionEditorHeading (_("Metering")));
736
737         ComboOption<float>* mht = new ComboOption<float> (
738                 "meter-hold",
739                 _("Meter hold time"),
740                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_hold),
741                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_hold)
742                 );
743
744         mht->add (MeterHoldOff, _("off"));
745         mht->add (MeterHoldShort, _("short"));
746         mht->add (MeterHoldMedium, _("medium"));
747         mht->add (MeterHoldLong, _("long"));
748
749         add_option (_("Misc"), mht);
750
751         ComboOption<float>* mfo = new ComboOption<float> (
752                 "meter-falloff",
753                 _("Meter fall-off"),
754                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_meter_falloff),
755                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_meter_falloff)
756                 );
757
758         mfo->add (METER_FALLOFF_OFF, _("off"));
759         mfo->add (METER_FALLOFF_SLOWEST, _("slowest"));
760         mfo->add (METER_FALLOFF_SLOW, _("slow"));
761         mfo->add (METER_FALLOFF_MEDIUM, _("medium"));
762         mfo->add (METER_FALLOFF_FAST, _("fast"));
763         mfo->add (METER_FALLOFF_FASTER, _("faster"));
764         mfo->add (METER_FALLOFF_FASTEST, _("fastest"));
765
766         add_option (_("Misc"), mfo);
767
768         add_option (_("Misc"), new OptionEditorHeading (_("Undo")));
769
770         add_option (_("Misc"), new UndoOptions (_rc_config));
771
772         add_option (_("Misc"), new OptionEditorHeading (_("Misc")));
773
774 #ifndef GTKOSX
775         /* font scaling does nothing with GDK/Quartz */
776         add_option (_("Misc"), new FontScalingOptions (_rc_config));
777 #endif
778
779         add_option (_("Misc"),
780              new BoolOption (
781                      "verify-remove-last-capture",
782                      _("Verify removal of last capture"),
783                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_verify_remove_last_capture),
784                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_verify_remove_last_capture)
785                      ));
786
787         add_option (_("Misc"),
788              new BoolOption (
789                      "periodic-safety-backups",
790                      _("Make periodic backups of the session file"),
791                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_periodic_safety_backups),
792                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_periodic_safety_backups)
793                      ));
794
795         add_option (_("Misc"),
796              new BoolOption (
797                      "sync-all-route-ordering",
798                      _("Syncronise editor and mixer track order"),
799                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_sync_all_route_ordering),
800                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_sync_all_route_ordering)
801                      ));
802
803         add_option (_("Misc"),
804              new BoolOption (
805                      "only-copy-imported-files",
806                      _("Always copy imported files"),
807                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_only_copy_imported_files),
808                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_only_copy_imported_files)
809                      ));
810
811         add_option (_("Misc"),
812              new BoolOption (
813                      "default-narrow_ms",
814                      _("Use narrow mixer strips"),
815                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_default_narrow_ms),
816                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_default_narrow_ms)
817                      ));
818
819         add_option (_("Misc"),
820              new BoolOption (
821                      "name-new-markers",
822                      _("Name new markers"),
823                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_name_new_markers),
824                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_name_new_markers)
825                      ));
826
827         add_option (_("Misc"), new OptionEditorHeading (_("Click")));
828         
829         add_option (_("Misc"), new ClickOptions (_rc_config, this));
830
831         /* TRANSPORT */
832
833         add_option (_("Transport"),
834              new BoolOption (
835                      "latched-record-enable",
836                      _("Keep record-enable engaged on stop"),
837                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_latched_record_enable),
838                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_latched_record_enable)
839                      ));
840
841         add_option (_("Transport"),
842              new BoolOption (
843                      "stop-recording-on-xrun",
844                      _("Stop recording when an xrun occurs"),
845                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_recording_on_xrun),
846                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_recording_on_xrun)
847                      ));
848
849         add_option (_("Transport"),
850              new BoolOption (
851                      "create-xrun-marker",
852                      _("Create markers where xruns occur"),
853                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_create_xrun_marker),
854                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_create_xrun_marker)
855                      ));
856
857         add_option (_("Transport"),
858              new BoolOption (
859                      "stop-at-session-end",
860                      _("Stop at the end of the session"),
861                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_stop_at_session_end),
862                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_stop_at_session_end)
863                      ));
864
865         add_option (_("Transport"),
866              new BoolOption (
867                      "primary-clock-delta-edit-cursor",
868                      _("Primary clock delta to edit cursor"),
869                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_primary_clock_delta_edit_cursor),
870                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_primary_clock_delta_edit_cursor)
871                      ));
872
873         add_option (_("Transport"),
874              new BoolOption (
875                      "secondary-clock-delta-edit-cursor",
876                      _("Secondary clock delta to edit cursor"),
877                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_secondary_clock_delta_edit_cursor),
878                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_secondary_clock_delta_edit_cursor)
879                      ));
880
881         add_option (_("Transport"),
882              new BoolOption (
883                      "disable-disarm-during-roll",
884                      _("Disable per-track record disarm while rolling"),
885                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_disable_disarm_during_roll),
886                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_disable_disarm_during_roll)
887                      ));
888
889         add_option (_("Transport"),
890              new BoolOption (
891                      "quieten_at_speed",
892                      _("12dB gain reduction during fast-forward and fast-rewind"),
893                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_quieten_at_speed),
894                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_quieten_at_speed)
895                      ));
896
897         /* EDITOR */
898
899         add_option (_("Editor"),
900              new BoolOption (
901                      "link-region-and-track-selection",
902                      _("Link selection of regions and tracks"),
903                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_link_region_and_track_selection),
904                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_link_region_and_track_selection)
905                      ));
906
907         add_option (_("Editor"),
908              new BoolOption (
909                      "automation-follows-regions",
910                      _("Move relevant automation when regions are moved"),
911                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_automation_follows_regions),
912                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_automation_follows_regions)
913                      ));
914
915         add_option (_("Editor"),
916              new BoolOption (
917                      "show-track-meters",
918                      _("Show meters on tracks in the editor"),
919                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_show_track_meters),
920                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_track_meters)
921                      ));
922
923         add_option (_("Editor"),
924              new BoolOption (
925                      "use-overlap-equivalency",
926                      _("Use overlap equivalency for regions"),
927                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_use_overlap_equivalency),
928                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_use_overlap_equivalency)
929                      ));
930
931         add_option (_("Editor"),
932              new BoolOption (
933                      "rubberbanding-snaps-to-grid",
934                      _("Make rubberband selection rectangle snap to the grid"),
935                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_rubberbanding_snaps_to_grid),
936                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_rubberbanding_snaps_to_grid)
937                      ));
938
939         add_option (_("Editor"),
940              new BoolOption (
941                      "show-waveforms",
942                      _("Show waveforms in regions"),
943                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_show_waveforms),
944                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_waveforms)
945                      ));
946
947         ComboOption<WaveformScale>* wfs = new ComboOption<WaveformScale> (
948                 "waveform-scale",
949                 _("Waveform scale"),
950                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_waveform_scale),
951                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_waveform_scale)
952                 );
953
954         wfs->add (Linear, _("linear"));
955         wfs->add (Logarithmic, _("logarithmic"));
956
957         add_option (_("Editor"), wfs);
958
959         ComboOption<WaveformShape>* wfsh = new ComboOption<WaveformShape> (
960                 "waveform-shape",
961                 _("Waveform shape"),
962                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_waveform_shape),
963                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_waveform_shape)
964                 );
965
966         wfsh->add (Traditional, _("traditional"));
967         wfsh->add (Rectified, _("rectified"));
968
969         add_option (_("Editor"), wfsh);
970
971         add_option (_("Editor"),
972              new BoolOption (
973                      "show-waveforms-while-recording",
974                      _("Show waveforms for audio while it is being recorded"),
975                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_show_waveforms_while_recording),
976                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_waveforms_while_recording)
977                      ));
978
979         /* AUDIO */
980
981         add_option (_("Audio"), new OptionEditorHeading (_("Buffering")));
982
983         add_option (_("Audio"), new BufferingOptions (_rc_config));
984
985         add_option (_("Audio"), new OptionEditorHeading (_("Monitoring")));
986
987         add_option (_("Audio"),
988              new BoolOption (
989                      "use-monitor-bus",
990                      _("Use a monitor bus (allows AFL/PFL and more control)"),
991                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_use_monitor_bus),
992                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_use_monitor_bus)
993                      ));
994
995         ComboOption<MonitorModel>* mm = new ComboOption<MonitorModel> (
996                 "monitoring-model",
997                 _("Monitoring handled by"),
998                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_monitoring_model),
999                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_monitoring_model)
1000                 );
1001
1002 #ifndef __APPLE__
1003         /* no JACK monitoring on CoreAudio */
1004         if (AudioEngine::instance()->can_request_hardware_monitoring()) {
1005                 mm->add (HardwareMonitoring, _("JACK"));
1006         }
1007 #endif
1008         mm->add (SoftwareMonitoring, _("ardour"));
1009         mm->add (ExternalMonitoring, _("audio hardware"));
1010
1011         add_option (_("Audio"), mm);
1012
1013         add_option (_("Audio"),
1014              new BoolOption (
1015                      "tape-machine-mode",
1016                      _("Tape machine mode"),
1017                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_tape_machine_mode),
1018                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_tape_machine_mode)
1019                      ));
1020
1021         add_option (_("Audio"), new OptionEditorHeading (_("Connection of tracks and busses")));
1022
1023         add_option (_("Audio"),
1024                     new BoolOption (
1025                             "auto-connect-standard-busses",
1026                             _("Auto-connect master/monitor busses"),
1027                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_connect_standard_busses),
1028                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_connect_standard_busses)
1029                             ));
1030
1031         ComboOption<AutoConnectOption>* iac = new ComboOption<AutoConnectOption> (
1032                 "input-auto-connect",
1033                 _("Connect track and bus inputs"),
1034                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_input_auto_connect),
1035                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_input_auto_connect)
1036                 );
1037
1038         iac->add (AutoConnectPhysical, _("automatically to physical inputs"));
1039         iac->add (ManualConnect, _("manually"));
1040
1041         add_option (_("Audio"), iac);
1042
1043         ComboOption<AutoConnectOption>* oac = new ComboOption<AutoConnectOption> (
1044                 "output-auto-connect",
1045                 _("Connect track and bus outputs"),
1046                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_output_auto_connect),
1047                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_output_auto_connect)
1048                 );
1049
1050         oac->add (AutoConnectPhysical, _("automatically to physical outputs"));
1051         oac->add (AutoConnectMaster, _("automatically to master outputs"));
1052         oac->add (ManualConnect, _("manually"));
1053
1054         add_option (_("Audio"), oac);
1055
1056         add_option (_("Audio"), new OptionEditorHeading (_("Denormals")));
1057
1058         add_option (_("Audio"),
1059              new BoolOption (
1060                      "denormal-protection",
1061                      _("Use DC bias to protect against denormals"),
1062                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_protection),
1063                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_protection)
1064                      ));
1065
1066         ComboOption<DenormalModel>* dm = new ComboOption<DenormalModel> (
1067                 "denormal-model",
1068                 _("Processor handling"),
1069                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_denormal_model),
1070                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_denormal_model)
1071                 );
1072
1073         dm->add (DenormalNone, _("no processor handling"));
1074
1075         FPU fpu;
1076
1077         if (fpu.has_flush_to_zero()) {
1078                 dm->add (DenormalFTZ, _("use FlushToZero"));
1079         }
1080
1081         if (fpu.has_denormals_are_zero()) {
1082                 dm->add (DenormalDAZ, _("use DenormalsAreZero"));
1083         }
1084
1085         if (fpu.has_flush_to_zero() && fpu.has_denormals_are_zero()) {
1086                 dm->add (DenormalFTZDAZ, _("use FlushToZero and DenormalsAreZerO"));
1087         }
1088
1089         add_option (_("Audio"), dm);
1090
1091         add_option (_("Audio"), new OptionEditorHeading (_("Plugins")));
1092
1093         add_option (_("Audio"),
1094              new BoolOption (
1095                      "plugins-stop-with-transport",
1096                      _("Stop plugins when the transport is stopped"),
1097                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_plugins_stop_with_transport),
1098                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_plugins_stop_with_transport)
1099                      ));
1100
1101         add_option (_("Audio"),
1102              new BoolOption (
1103                      "do-not-record-plugins",
1104                      _("Disable plugins during recording"),
1105                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_do_not_record_plugins),
1106                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_do_not_record_plugins)
1107                      ));
1108
1109         add_option (_("Audio"),
1110              new BoolOption (
1111                      "new-plugins-active",
1112                      _("Make new plugins active"),
1113                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_new_plugins_active),
1114                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_new_plugins_active)
1115                      ));
1116
1117         add_option (_("Audio"),
1118              new BoolOption (
1119                      "auto-analyse-audio",
1120                      _("Enable automatic analysis of audio"),
1121                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_auto_analyse_audio),
1122                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_auto_analyse_audio)
1123                      ));
1124
1125         /* SOLO AND MUTE */
1126
1127         add_option (_("Solo / mute"),
1128              new FaderOption (
1129                      "solo-mute-gain",
1130                      _("Solo mute cut (dB)"),
1131                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_gain),
1132                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_gain)
1133                      ));
1134                      
1135         add_option (_("Solo / mute"),
1136              new BoolOption (
1137                      "solo-control-is-listen-control",
1138                      _("Solo controls are Listen controls"),
1139                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_control_is_listen_control),
1140                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_control_is_listen_control)
1141                      ));
1142
1143         ComboOption<ListenPosition>* lp = new ComboOption<ListenPosition> (
1144                 "listen-position",
1145                 _("Listen Position"),
1146                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_listen_position),
1147                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_listen_position)
1148                 );
1149
1150         lp->add (AfterFaderListen, _("after-fader listen"));
1151         lp->add (PreFaderListen, _("pre-fader listen"));
1152
1153         add_option (_("Solo / mute"), lp);
1154
1155         add_option (_("Solo / mute"),
1156              new BoolOption (
1157                      "exclusive-solo",
1158                      _("Exclusive solo"),
1159                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_exclusive_solo),
1160                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_exclusive_solo)
1161                      ));
1162
1163         add_option (_("Solo / mute"),
1164              new BoolOption (
1165                      "show-solo-mutes",
1166                      _("Show solo muting"),
1167                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_show_solo_mutes),
1168                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_show_solo_mutes)
1169                      ));
1170
1171         add_option (_("Solo / mute"),
1172              new BoolOption (
1173                      "solo-mute-override",
1174                      _("Soloing overrides muting"),
1175                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_override),
1176                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_override)
1177                      ));
1178
1179         add_option (_("Solo / mute"), new OptionEditorHeading (_("Default track / bus muting options")));
1180         
1181         add_option (_("Solo / mute"),
1182              new BoolOption (
1183                      "mute-affects-pre-fader",
1184                      _("Mute affects pre-fader sends"),
1185                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_pre_fader),
1186                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_pre_fader)
1187                      ));
1188
1189         add_option (_("Solo / mute"),
1190              new BoolOption (
1191                      "mute-affects-post-fader",
1192                      _("Mute affects post-fader sends"),
1193                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_post_fader),
1194                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_post_fader)
1195                      ));
1196         
1197         add_option (_("Solo / mute"),
1198              new BoolOption (
1199                      "mute-affects-control-outs",
1200                      _("Mute affects control outputs"),
1201                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_control_outs),
1202                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_control_outs)
1203                      ));
1204         
1205         add_option (_("Solo / mute"),
1206              new BoolOption (
1207                      "mute-affects-main-outs",
1208                      _("Mute affects main outputs"),
1209                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mute_affects_main_outs),
1210                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mute_affects_main_outs)
1211                      ));
1212
1213         add_option (_("MIDI control"),
1214                     new BoolOption (
1215                             "send-mtc",
1216                             _("Send MIDI Time Code"),
1217                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mtc),
1218                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mtc)
1219                             ));
1220
1221         add_option (_("MIDI control"),
1222                     new BoolOption (
1223                             "mmc-control",
1224                             _("Obey MIDI Machine Control commands"),
1225                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_control),
1226                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_control)
1227                             ));
1228
1229
1230         add_option (_("MIDI control"),
1231                     new BoolOption (
1232                             "send-mmc",
1233                             _("Send MIDI Machine Control commands"),
1234                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_send_mmc),
1235                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_send_mmc)
1236                             ));
1237
1238         add_option (_("MIDI control"),
1239                     new BoolOption (
1240                             "midi-feedback",
1241                             _("Send MIDI control feedback"),
1242                             sigc::mem_fun (*_rc_config, &RCConfiguration::get_midi_feedback),
1243                             sigc::mem_fun (*_rc_config, &RCConfiguration::set_midi_feedback)
1244                             ));
1245
1246         add_option (_("MIDI control"),
1247              new SpinOption<uint8_t> (
1248                      "mmc-receive-device-id",
1249                      _("Inbound MMC device ID"),
1250                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_receive_device_id),
1251                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_receive_device_id),
1252                      0, 128, 1, 10
1253                      ));
1254
1255         add_option (_("MIDI control"),
1256              new SpinOption<uint8_t> (
1257                      "mmc-send-device-id",
1258                      _("Outbound MMC device ID"),
1259                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_mmc_send_device_id),
1260                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_mmc_send_device_id),
1261                      0, 128, 1, 10
1262                      ));
1263
1264         add_option (_("MIDI control"),
1265              new SpinOption<int32_t> (
1266                      "initial-program-change",
1267                      _("Initial program change"),
1268                      sigc::mem_fun (*_rc_config, &RCConfiguration::get_initial_program_change),
1269                      sigc::mem_fun (*_rc_config, &RCConfiguration::set_initial_program_change),
1270                      -1, 65536, 1, 10
1271                      ));
1272
1273         /* CONTROL SURFACES */
1274
1275         add_option (_("Control surfaces"), new ControlSurfacesOptions (*this));
1276
1277         ComboOption<RemoteModel>* rm = new ComboOption<RemoteModel> (
1278                 "remote-model",
1279                 _("Control surface remote ID"),
1280                 sigc::mem_fun (*_rc_config, &RCConfiguration::get_remote_model),
1281                 sigc::mem_fun (*_rc_config, &RCConfiguration::set_remote_model)
1282                 );
1283
1284         rm->add (UserOrdered, _("assigned by user"));
1285         rm->add (MixerOrdered, _("follows order of mixer"));
1286         rm->add (EditorOrdered, _("follows order of editor"));
1287
1288         add_option (_("Control surfaces"), rm);
1289
1290         /* KEYBOARD */
1291
1292         add_option (_("Keyboard"), new KeyboardOptions);
1293 }
1294
1295