90855a4ded818a5caa29b41485079cf4525806db
[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 "pbd/fpu.h"
6 #include "midi++/manager.h"
7 #include "midi++/factory.h"
8 #include "ardour/rc_configuration.h"
9 #include "rc_option_editor.h"
10 #include "utils.h"
11 #include "midi_port_dialog.h"
12 #include "sfdb_ui.h"
13 #include "keyboard.h"
14 #include "i18n.h"
15
16 using namespace std;
17 using namespace sigc;
18 using namespace Gtk;
19 using namespace Gtkmm2ext;
20 using namespace PBD;
21 using namespace ARDOUR;
22
23 class MIDIPorts : public OptionEditorBox
24 {
25 public:
26         MIDIPorts (RCConfiguration* c)
27                 : _rc_config (c),
28                   _add_port_button (Stock::ADD)
29         {
30                 _store = ListStore::create (_model);
31                 _view.set_model (_store);
32                 _view.append_column (_("Name"), _model.name);
33                 _view.append_column_editable (_("Online"), _model.online);
34                 _view.append_column_editable (_("Trace input"), _model.trace_input);
35                 _view.append_column_editable (_("Trace output"), _model.trace_output);
36
37                 HBox* h = manage (new HBox);
38                 h->set_spacing (4);
39                 h->pack_start (_view, true, true);
40
41                 VBox* v = manage (new VBox);
42                 v->set_spacing (4);
43                 v->pack_start (_add_port_button, false, false);
44                 h->pack_start (*v, false, false);
45
46                 _box->pack_start (*h);
47
48                 Table* t = manage (new Table (2, 4));
49                 t->set_spacings (12);
50
51                 int n = 0;
52                 Label* l = manage (new Label (_("MTC:")));
53                 l->set_alignment (1, 0.5);
54                 t->attach (*l, 0, 1, n, n + 1, EXPAND | FILL, FILL);
55                 t->attach (_mtc_combo, 1, 2, n, n + 1, EXPAND | FILL, EXPAND | FILL);
56                 ++n;
57                 
58                 l = manage (new Label (_("MIDI clock:")));
59                 l->set_alignment (1, 0.5);
60                 t->attach (*l, 0, 1, n, n + 1, FILL, FILL);
61                 t->attach (_midi_clock_combo, 1, 2, n, n + 1, FILL, FILL);
62                 ++n;
63
64                 l = manage (new Label (_("MMC:")));
65                 l->set_alignment (1, 0.5);
66                 t->attach (*l, 0, 1, n, n + 1, FILL, FILL);
67                 t->attach (_mmc_combo, 1, 2, n, n + 1, FILL, FILL);
68                 ++n;
69
70                 l = manage (new Label (_("MIDI parameter control:")));
71                 l->set_alignment (1, 0.5);
72                 t->attach (*l, 0, 1, n, n + 1, FILL, FILL);
73                 t->attach (_mpc_combo, 1, 2, n, n + 1, FILL, FILL);
74                 ++n;
75
76                 _box->pack_start (*t, true, true);
77
78                 ports_changed ();
79
80                 _add_port_button.signal_clicked().connect (mem_fun (*this, &MIDIPorts::add_port_clicked));
81                 _mtc_combo.signal_changed().connect (mem_fun (*this, &MIDIPorts::mtc_combo_changed));
82                 _mmc_combo.signal_changed().connect (mem_fun (*this, &MIDIPorts::mmc_combo_changed));
83                 _mpc_combo.signal_changed().connect (mem_fun (*this, &MIDIPorts::mpc_combo_changed));
84                 _midi_clock_combo.signal_changed().connect (mem_fun (*this, &MIDIPorts::midi_clock_combo_changed));
85         }
86
87         void parameter_changed (string const & p)
88         {
89                 if (p == "mtc-port-name") {
90                         _mtc_combo.set_active_text (_rc_config->get_mtc_port_name());
91                 } else if (p == "mmc-port-name") {
92                         _mmc_combo.set_active_text (_rc_config->get_mmc_port_name());
93                 } else if (p == "midi-port-name") {
94                         _mpc_combo.set_active_text (_rc_config->get_midi_port_name());
95                 } else if (p == "midi-clock-port-name") {
96                         _midi_clock_combo.set_active_text (_rc_config->get_midi_clock_port_name());
97                 } 
98         }
99
100         void set_state_from_config ()
101         {
102                 parameter_changed ("mtc-port-name");
103                 parameter_changed ("mmc-port-name");
104                 parameter_changed ("midi-port-name");
105                 parameter_changed ("midi-clock-port-name");
106         }
107
108         void mtc_combo_changed ()
109         {
110                 _rc_config->set_mtc_port_name (_mtc_combo.get_active_text());
111         }
112
113         void mmc_combo_changed ()
114         {
115                 _rc_config->set_mmc_port_name (_mmc_combo.get_active_text());
116         }
117
118         void mpc_combo_changed ()
119         {
120                 _rc_config->set_midi_port_name (_mpc_combo.get_active_text());
121         }
122
123         void midi_clock_combo_changed ()
124         {
125                 _rc_config->set_midi_clock_port_name (_midi_clock_combo.get_active_text());
126         }
127         
128 private:
129
130         void setup_ports_combo (ComboBoxText& c)
131         {
132                 c.clear_items ();
133                 MIDI::Manager::PortMap const & ports = MIDI::Manager::instance()->get_midi_ports ();
134                 for (MIDI::Manager::PortMap::const_iterator i = ports.begin(); i != ports.end(); ++i) {
135                         c.append_text (i->first);
136                 }
137         }
138
139         void ports_changed ()
140         {
141                 /* XXX: why is this coming from here? */
142                 MIDI::Manager::PortMap const & ports = MIDI::Manager::instance()->get_midi_ports ();
143
144                 _store->clear ();
145
146                 for (MIDI::Manager::PortMap::const_iterator i = ports.begin(); i != ports.end(); ++i) {
147                         TreeModel::Row r = *_store->append ();
148                         r[_model.name] = i->first;
149                         r[_model.online] = !i->second->input()->offline();
150                         r[_model.trace_input] = i->second->input()->tracing();
151                         r[_model.trace_output] = i->second->output()->tracing();
152                 }
153
154                 setup_ports_combo (_mtc_combo);
155                 setup_ports_combo (_midi_clock_combo);
156                 setup_ports_combo (_mmc_combo);
157                 setup_ports_combo (_mpc_combo);
158         }
159
160         void add_port_clicked ()
161         {
162                 MidiPortDialog dialog;
163
164                 dialog.set_position (WIN_POS_MOUSE);
165
166                 dialog.show ();
167                 
168                 int const r = dialog.run ();
169
170                 switch (r) {
171                 case RESPONSE_ACCEPT:
172                         break;
173                 default:
174                         return;
175                         break;
176                 }
177
178                 Glib::ustring const mode = dialog.port_mode_combo.get_active_text ();
179                 string smod;
180
181                 if (mode == _("input")) {
182                         smod = X_("input");
183                 } else if (mode == (_("output"))) {
184                         smod = X_("output");
185                 } else {
186                         smod = "duplex";
187                 }
188
189                 XMLNode node (X_("MIDI-port"));
190                 
191                 node.add_property ("tag", dialog.port_name.get_text());
192                 node.add_property ("device", X_("ardour")); // XXX this can't be right for all types
193                 node.add_property ("type", MIDI::PortFactory::default_port_type());
194                 node.add_property ("mode", smod);
195                 
196                 if (MIDI::Manager::instance()->add_port (node) != 0) {
197                         ports_changed ();
198                 }
199         }
200         
201         class MIDIModelColumns : public TreeModelColumnRecord
202         {
203         public:
204                 MIDIModelColumns ()
205                 {
206                         add (name);
207                         add (online);
208                         add (trace_input);
209                         add (trace_output);
210                 }
211
212                 TreeModelColumn<string> name;
213                 TreeModelColumn<bool> online;
214                 TreeModelColumn<bool> trace_input;
215                 TreeModelColumn<bool> trace_output;
216         };
217
218         RCConfiguration* _rc_config;
219         Glib::RefPtr<ListStore> _store;
220         MIDIModelColumns _model;
221         TreeView _view;
222         Button _add_port_button;
223         ComboBoxText _mtc_combo;
224         ComboBoxText _midi_clock_combo;
225         ComboBoxText _mmc_combo;
226         ComboBoxText _mpc_combo;
227 };
228
229
230 class ClickOptions : public OptionEditorBox
231 {
232 public:
233         ClickOptions (RCConfiguration* c, ArdourDialog* p)
234                 : _rc_config (c),
235                   _parent (p)
236         {
237                 Table* t = manage (new Table (2, 3));
238                 t->set_spacings (4);
239
240                 Label* l = manage (new Label (_("Click audio file:")));
241                 l->set_alignment (1, 0.5);
242                 t->attach (*l, 0, 1, 0, 1, FILL);
243                 t->attach (_click_path_entry, 1, 2, 0, 1, FILL);
244                 Button* b = manage (new Button (_("Browse...")));
245                 b->signal_clicked().connect (mem_fun (*this, &ClickOptions::click_browse_clicked));
246                 t->attach (*b, 2, 3, 0, 1, FILL);
247
248                 l = manage (new Label (_("Click emphasis audio file:")));
249                 l->set_alignment (1, 0.5);
250                 t->attach (*l, 0, 1, 1, 2, FILL);
251                 t->attach (_click_emphasis_path_entry, 1, 2, 1, 2, FILL);
252                 b = manage (new Button (_("Browse...")));
253                 b->signal_clicked().connect (mem_fun (*this, &ClickOptions::click_emphasis_browse_clicked));
254                 t->attach (*b, 2, 3, 1, 2, FILL);
255
256                 _box->pack_start (*t, false, false);
257         }
258         
259         void parameter_changed (string const & p)
260         {
261                 if (p == "click-sound") {
262                         _click_path_entry.set_text (_rc_config->get_click_sound());
263                 } else if (p == "click-emphasis-sound") {
264                         _click_emphasis_path_entry.set_text (_rc_config->get_click_emphasis_sound());
265                 }
266         }
267
268         void set_state_from_config ()
269         {
270                 parameter_changed ("click-sound");
271                 parameter_changed ("click-emphasis-sound");
272         }
273
274 private:        
275
276         void click_browse_clicked ()
277         {
278                 SoundFileChooser sfdb (*_parent, _("Choose Click"));
279
280                 sfdb.show_all ();
281                 sfdb.present ();
282                 
283                 if (sfdb.run () == RESPONSE_OK) {
284                         click_chosen (sfdb.get_filename());
285                 }
286         }
287
288         void click_chosen (string const & path)
289         {
290                 _click_path_entry.set_text (path);
291                 _rc_config->set_click_sound (path);
292         }
293
294         void click_emphasis_browse_clicked ()
295         {
296                 SoundFileChooser sfdb (*_parent, _("Choose Click Emphasis"));
297
298                 sfdb.show_all ();
299                 sfdb.present ();
300                 
301                 if (sfdb.run () == RESPONSE_OK) {
302                         click_emphasis_chosen (sfdb.get_filename());
303                 }
304         }
305
306         void click_emphasis_chosen (string const & path)
307         {
308                 _click_emphasis_path_entry.set_text (path);
309                 _rc_config->set_click_emphasis_sound (path);
310         }
311
312         RCConfiguration* _rc_config;
313         ArdourDialog* _parent;
314         Entry _click_path_entry;
315         Entry _click_emphasis_path_entry;
316 };
317
318 class UndoOptions : public OptionEditorBox
319 {
320 public:
321         UndoOptions (RCConfiguration* c) :
322                 _rc_config (c),
323                 _limit_undo_button (_("Limit undo history to")),
324                 _save_undo_button (_("Save undo history of"))
325         {
326                 Table* t = new Table (2, 3);
327                 t->set_spacings (4);
328
329                 t->attach (_limit_undo_button, 0, 1, 0, 1, FILL);
330                 _limit_undo_spin.set_range (0, 512);
331                 _limit_undo_spin.set_increments (1, 10);
332                 t->attach (_limit_undo_spin, 1, 2, 0, 1, FILL | EXPAND);
333                 Label* l = manage (new Label (_("commands")));
334                 l->set_alignment (0, 0.5);
335                 t->attach (*l, 2, 3, 0, 1);
336
337                 t->attach (_save_undo_button, 0, 1, 1, 2, FILL);
338                 _save_undo_spin.set_range (0, 512);
339                 _save_undo_spin.set_increments (1, 10);
340                 t->attach (_save_undo_spin, 1, 2, 1, 2, FILL | EXPAND);
341                 l = manage (new Label (_("commands")));
342                 l->set_alignment (0, 0.5);
343                 t->attach (*l, 2, 3, 1, 2);
344
345                 _box->pack_start (*t);
346
347                 _limit_undo_button.signal_toggled().connect (mem_fun (*this, &UndoOptions::limit_undo_toggled));
348                 _limit_undo_spin.signal_value_changed().connect (mem_fun (*this, &UndoOptions::limit_undo_changed));
349                 _save_undo_button.signal_toggled().connect (mem_fun (*this, &UndoOptions::save_undo_toggled));
350                 _save_undo_spin.signal_value_changed().connect (mem_fun (*this, &UndoOptions::save_undo_changed));
351         }
352
353         void parameter_changed (string const & p)
354         {
355                 if (p == "history-depth") {
356                         int32_t const d = _rc_config->get_history_depth();
357                         _limit_undo_button.set_active (d != 0);
358                         _limit_undo_spin.set_sensitive (d != 0);
359                         _limit_undo_spin.set_value (d);
360                 } else if (p == "save-history") {
361                         bool const x = _rc_config->get_save_history ();
362                         _save_undo_button.set_active (x);
363                         _save_undo_spin.set_sensitive (x);
364                 } else if (p == "save-history-depth") {
365                         int32_t const d = _rc_config->get_saved_history_depth();
366                         _save_undo_spin.set_value (_rc_config->get_saved_history_depth());
367                 }
368         }
369
370         void set_state_from_config ()
371         {
372                 parameter_changed ("save-history");
373                 parameter_changed ("history-depth");
374                 parameter_changed ("save-history-depth");
375         }
376
377         void limit_undo_toggled ()
378         {
379                 bool const x = _limit_undo_button.get_active ();
380                 _limit_undo_spin.set_sensitive (x);
381                 int32_t const n = x ? 16 : 0;
382                 _limit_undo_spin.set_value (n);
383                 _rc_config->set_history_depth (n);
384         }
385
386         void limit_undo_changed ()
387         {
388                 _rc_config->set_history_depth (_limit_undo_spin.get_value_as_int ());
389         }
390
391         void save_undo_toggled ()
392         {
393                 bool const x = _save_undo_button.get_active ();
394                 _rc_config->set_save_history (x);
395         }
396
397         void save_undo_changed ()
398         {
399                 _rc_config->set_saved_history_depth (_save_undo_spin.get_value_as_int ());
400         }
401         
402 private:
403         RCConfiguration* _rc_config;
404         CheckButton _limit_undo_button;
405         SpinButton _limit_undo_spin;
406         CheckButton _save_undo_button;
407         SpinButton _save_undo_spin;
408 };
409
410
411
412 static const struct {
413     const char *name;
414     guint modifier;
415 } modifiers[] = {
416
417 #ifdef GTKOSX
418
419         /* Command = Meta
420            Option/Alt = Mod1
421         */
422
423         { "Shift", GDK_SHIFT_MASK },
424         { "Command", GDK_META_MASK },
425         { "Control", GDK_CONTROL_MASK },
426         { "Option", GDK_MOD1_MASK },
427         { "Command-Shift", GDK_MOD1_MASK|GDK_SHIFT_MASK },
428         { "Command-Option", GDK_MOD1_MASK|GDK_MOD5_MASK },
429         { "Shift-Option", GDK_SHIFT_MASK|GDK_MOD5_MASK },
430         { "Shift-Command-Option", GDK_MOD5_MASK|GDK_SHIFT_MASK|GDK_MOD1_MASK },
431
432 #else
433         { "Shift", GDK_SHIFT_MASK },
434         { "Control", GDK_CONTROL_MASK },
435         { "Alt (Mod1)", GDK_MOD1_MASK },
436         { "Control-Shift", GDK_CONTROL_MASK|GDK_SHIFT_MASK },
437         { "Control-Alt", GDK_CONTROL_MASK|GDK_MOD1_MASK },
438         { "Shift-Alt", GDK_SHIFT_MASK|GDK_MOD1_MASK },
439         { "Control-Shift-Alt", GDK_CONTROL_MASK|GDK_SHIFT_MASK|GDK_MOD1_MASK },
440         { "Mod2", GDK_MOD2_MASK },
441         { "Mod3", GDK_MOD3_MASK },
442         { "Mod4", GDK_MOD4_MASK },
443         { "Mod5", GDK_MOD5_MASK },
444 #endif
445         { 0, 0 }
446 };
447
448
449 class KeyboardOptions : public OptionEditorBox
450 {
451 public:
452         KeyboardOptions () :
453                   _delete_button_adjustment (3, 1, 5),
454                   _delete_button_spin (_delete_button_adjustment),
455                   _edit_button_adjustment (3, 1, 5),
456                   _edit_button_spin (_edit_button_adjustment)
457                 
458         {
459                 /* internationalize and prepare for use with combos */
460
461                 vector<string> dumb;
462                 for (int i = 0; modifiers[i].name; ++i) {
463                         dumb.push_back (_(modifiers[i].name));
464                 }
465
466                 set_popdown_strings (_edit_modifier_combo, dumb);
467                 _edit_modifier_combo.signal_changed().connect (mem_fun(*this, &KeyboardOptions::edit_modifier_chosen));
468
469                 for (int x = 0; modifiers[x].name; ++x) {
470                         if (modifiers[x].modifier == Keyboard::edit_modifier ()) {
471                                 _edit_modifier_combo.set_active_text (_(modifiers[x].name));
472                                 break;
473                         }
474                 }
475
476                 Table* t = manage (new Table (4, 4));
477                 t->set_spacings (4);
478
479                 Label* l = manage (new Label (_("Edit using:")));
480                 l->set_name ("OptionsLabel");
481                 l->set_alignment (1.0, 0.5);
482
483                 t->attach (*l, 0, 1, 0, 1, FILL | EXPAND, FILL);
484                 t->attach (_edit_modifier_combo, 1, 2, 0, 1, FILL | EXPAND, FILL);
485
486                 l = manage (new Label (_("+ button")));
487                 l->set_name ("OptionsLabel");
488
489                 t->attach (*l, 3, 4, 0, 1, FILL | EXPAND, FILL);
490                 t->attach (_edit_button_spin, 4, 5, 0, 1, FILL | EXPAND, FILL);
491
492                 _edit_button_spin.set_name ("OptionsEntry");
493                 _edit_button_adjustment.set_value (Keyboard::edit_button());
494                 _edit_button_adjustment.signal_value_changed().connect (mem_fun(*this, &KeyboardOptions::edit_button_changed));
495
496                 set_popdown_strings (_delete_modifier_combo, dumb);
497                 _delete_modifier_combo.signal_changed().connect (mem_fun(*this, &KeyboardOptions::delete_modifier_chosen));
498
499                 for (int x = 0; modifiers[x].name; ++x) {
500                         if (modifiers[x].modifier == Keyboard::delete_modifier ()) {
501                                 _delete_modifier_combo.set_active_text (_(modifiers[x].name));
502                                 break;
503                         }
504                 }
505
506                 l = manage (new Label (_("Delete using:")));
507                 l->set_name ("OptionsLabel");
508                 l->set_alignment (1.0, 0.5);
509
510                 t->attach (*l, 0, 1, 1, 2, FILL | EXPAND, FILL);
511                 t->attach (_delete_modifier_combo, 1, 2, 1, 2, FILL | EXPAND, FILL);
512
513                 l = manage (new Label (_("+ button")));
514                 l->set_name ("OptionsLabel");
515
516                 t->attach (*l, 3, 4, 1, 2, FILL | EXPAND, FILL);
517                 t->attach (_delete_button_spin, 4, 5, 1, 2, FILL | EXPAND, FILL);
518
519                 _delete_button_spin.set_name ("OptionsEntry");
520                 _delete_button_adjustment.set_value (Keyboard::delete_button());
521                 _delete_button_adjustment.signal_value_changed().connect (mem_fun(*this, &KeyboardOptions::delete_button_changed));
522
523                 set_popdown_strings (_snap_modifier_combo, dumb);
524                 _snap_modifier_combo.signal_changed().connect (mem_fun(*this, &KeyboardOptions::snap_modifier_chosen));
525
526                 for (int x = 0; modifiers[x].name; ++x) {
527                         if (modifiers[x].modifier == (guint) Keyboard::snap_modifier ()) {
528                                 _snap_modifier_combo.set_active_text (_(modifiers[x].name));
529                                 break;
530                         }
531                 }
532
533                 l = manage (new Label (_("Ignore snap using:")));
534                 l->set_name ("OptionsLabel");
535                 l->set_alignment (1.0, 0.5);
536
537                 t->attach (*l, 0, 1, 2, 3, FILL | EXPAND, FILL);
538                 t->attach (_snap_modifier_combo, 1, 2, 2, 3, FILL | EXPAND, FILL);
539
540                 vector<string> strs;
541
542                 for (map<string,string>::iterator bf = Keyboard::binding_files.begin(); bf != Keyboard::binding_files.end(); ++bf) {
543                         strs.push_back (bf->first);
544                 }
545
546                 set_popdown_strings (_keyboard_layout_selector, strs);
547                 _keyboard_layout_selector.set_active_text (Keyboard::current_binding_name());
548                 _keyboard_layout_selector.signal_changed().connect (mem_fun (*this, &KeyboardOptions::bindings_changed));
549
550                 l = manage (new Label (_("Keyboard layout:")));
551                 l->set_name ("OptionsLabel");
552                 l->set_alignment (1.0, 0.5);
553
554                 t->attach (*l, 0, 1, 3, 4, FILL | EXPAND, FILL);
555                 t->attach (_keyboard_layout_selector, 1, 2, 3, 4, FILL | EXPAND, FILL);
556
557                 _box->pack_start (*t, false, false);
558         }
559
560         void parameter_changed (string const & p)
561         {
562                 /* XXX: these aren't really config options... */
563         }
564
565         void set_state_from_config ()
566         {
567                 /* XXX: these aren't really config options... */
568         }
569
570 private:
571
572         void bindings_changed ()
573         {
574                 string const txt = _keyboard_layout_selector.get_active_text();
575
576                 /* XXX: config...?  for all this keyboard stuff */
577                 
578                 for (map<string,string>::iterator i = Keyboard::binding_files.begin(); i != Keyboard::binding_files.end(); ++i) {
579                         if (txt == i->first) {
580                                 if (Keyboard::load_keybindings (i->second)) {
581                                         Keyboard::save_keybindings ();
582                                 }
583                         }
584                 }
585         }
586
587         void edit_modifier_chosen ()
588         {
589                 string const txt = _edit_modifier_combo.get_active_text();
590                 
591                 for (int i = 0; modifiers[i].name; ++i) {
592                         if (txt == _(modifiers[i].name)) {
593                                 Keyboard::set_edit_modifier (modifiers[i].modifier);
594                                 break;
595                         }
596                 }
597         }
598
599         void delete_modifier_chosen ()
600         {
601                 string const txt = _delete_modifier_combo.get_active_text();
602                 
603                 for (int i = 0; modifiers[i].name; ++i) {
604                         if (txt == _(modifiers[i].name)) {
605                                 Keyboard::set_delete_modifier (modifiers[i].modifier);
606                                 break;
607                         }
608                 }
609         }
610         
611         void snap_modifier_chosen ()
612         {
613                 string const txt = _snap_modifier_combo.get_active_text();
614                 
615                 for (int i = 0; modifiers[i].name; ++i) {
616                         if (txt == _(modifiers[i].name)) {
617                                 Keyboard::set_snap_modifier (modifiers[i].modifier);
618                                 break;
619                         }
620                 }
621         }
622
623         void delete_button_changed ()
624         {
625                 Keyboard::set_delete_button (_delete_button_spin.get_value_as_int());
626         }
627
628         void edit_button_changed ()
629         {
630                 Keyboard::set_edit_button (_edit_button_spin.get_value_as_int());
631         }
632         
633         ComboBoxText _keyboard_layout_selector;
634         ComboBoxText _edit_modifier_combo;
635         ComboBoxText _delete_modifier_combo;
636         ComboBoxText _snap_modifier_combo;
637         Adjustment _delete_button_adjustment;
638         SpinButton _delete_button_spin;
639         Adjustment _edit_button_adjustment;
640         SpinButton _edit_button_spin;
641 };
642
643 class FontScalingOptions : public OptionEditorBox
644 {
645 public:
646         FontScalingOptions (RCConfiguration* c) :
647                 _rc_config (c),
648                 _dpi_adjustment (50, 50, 250, 1, 10),
649                 _dpi_slider (_dpi_adjustment)
650         {
651                 _dpi_adjustment.set_value (_rc_config->get_font_scale ());
652
653                 Label* l = manage (new Label (_("Font scaling:")));
654                 l->set_name ("OptionsLabel");
655
656                 _dpi_slider.set_update_policy (UPDATE_DISCONTINUOUS);
657                 HBox* h = manage (new HBox);
658                 h->set_spacing (4);
659                 h->pack_start (*l, false, false);
660                 h->pack_start (_dpi_slider, true, true);
661
662                 _box->pack_start (*h, false, false);
663
664                 _dpi_adjustment.signal_value_changed().connect (mem_fun (*this, &FontScalingOptions::dpi_changed));
665         }
666
667         void parameter_changed (string const & p)
668         {
669                 if (p == "font-scale") {
670                         _dpi_adjustment.set_value (_rc_config->get_font_scale() / 1024.);
671                 }
672         }
673
674         void set_state_from_config ()
675         {
676                 parameter_changed ("font-scale");
677         }
678         
679 private:
680         
681         void dpi_changed ()
682         {
683                 _rc_config->set_font_scale ((long) floor (_dpi_adjustment.get_value() * 1024));
684                 /* XXX: should be triggered from the parameter changed signal */
685                 reset_dpi ();
686         }
687
688         RCConfiguration* _rc_config;
689         Adjustment _dpi_adjustment;
690         HScale _dpi_slider;
691 };
692
693 RCOptionEditor::RCOptionEditor ()
694         : OptionEditor (Config, _("Ardour Preferences")),
695           _rc_config (Config)
696 {
697         /* MISC */
698
699         add (_("Misc"), new OptionEditorHeading (_("Metering")));
700         
701         ComboOption<float>* mht = new ComboOption<float> (
702                 "meter-hold",
703                 _("Meter hold time"),
704                 mem_fun (*_rc_config, &RCConfiguration::get_meter_hold),
705                 mem_fun (*_rc_config, &RCConfiguration::set_meter_hold)
706                 );
707
708         mht->add (MeterHoldOff, _("off"));
709         mht->add (MeterHoldShort, _("short"));
710         mht->add (MeterHoldMedium, _("medium"));
711         mht->add (MeterHoldLong, _("long"));
712         
713         add (_("Misc"), mht);
714
715         ComboOption<float>* mfo = new ComboOption<float> (
716                 "meter-falloff",
717                 _("Meter fall-off"),
718                 mem_fun (*_rc_config, &RCConfiguration::get_meter_falloff),
719                 mem_fun (*_rc_config, &RCConfiguration::set_meter_falloff)
720                 );
721
722         mfo->add (METER_FALLOFF_OFF, _("off"));
723         mfo->add (METER_FALLOFF_SLOWEST, _("slowest"));
724         mfo->add (METER_FALLOFF_SLOW, _("slow"));
725         mfo->add (METER_FALLOFF_MEDIUM, _("medium"));
726         mfo->add (METER_FALLOFF_FAST, _("fast"));
727         mfo->add (METER_FALLOFF_FASTER, _("faster"));
728         mfo->add (METER_FALLOFF_FASTEST, _("fastest"));
729
730         add (_("Misc"), mfo);
731
732         add (_("Misc"), new OptionEditorHeading (_("Undo")));
733         
734         add (_("Misc"), new UndoOptions (_rc_config));
735
736         add (_("Misc"), new OptionEditorHeading (_("Misc")));
737         
738         ComboOption<RemoteModel>* rm = new ComboOption<RemoteModel> (
739                 "remote-model",
740                 _("Control surface remote ID"),
741                 mem_fun (*_rc_config, &RCConfiguration::get_remote_model),
742                 mem_fun (*_rc_config, &RCConfiguration::set_remote_model)
743                 );
744
745         rm->add (UserOrdered, _("assigned by user"));
746         rm->add (MixerOrdered, _("follows order of mixer"));
747         rm->add (EditorOrdered, _("follows order of editor"));
748
749         add (_("Misc"), rm);
750
751 #ifndef GTKOSX
752         /* font scaling does nothing with GDK/Quartz */
753         add (_("Misc"), new FontScalingOptions (_rc_config));
754 #endif  
755
756         add (_("Misc"),
757              new BoolOption (
758                      "verify-remove-last-capture",
759                      _("Verify removal of last capture"),
760                      mem_fun (*_rc_config, &RCConfiguration::get_verify_remove_last_capture),
761                      mem_fun (*_rc_config, &RCConfiguration::set_verify_remove_last_capture)
762                      ));
763         
764         add (_("Misc"),
765              new BoolOption (
766                      "periodic-safety-backups",
767                      _("Make periodic backups of the session file"),
768                      mem_fun (*_rc_config, &RCConfiguration::get_periodic_safety_backups),
769                      mem_fun (*_rc_config, &RCConfiguration::set_periodic_safety_backups)
770                      ));
771
772         add (_("Misc"),
773              new BoolOption (
774                      "sync-all-route-ordering",
775                      _("Syncronise editor and mixer track order"),
776                      mem_fun (*_rc_config, &RCConfiguration::get_sync_all_route_ordering),
777                      mem_fun (*_rc_config, &RCConfiguration::set_sync_all_route_ordering)
778                      ));
779
780         add (_("Misc"),
781              new BoolOption (
782                      "only-copy-imported-files",
783                      _("Always copy imported files"),
784                      mem_fun (*_rc_config, &RCConfiguration::get_only_copy_imported_files),
785                      mem_fun (*_rc_config, &RCConfiguration::set_only_copy_imported_files)
786                      ));
787
788         add (_("Misc"),
789              new BoolOption (
790                      "default-narrow_ms",
791                      _("Use narrow mixer strips"),
792                      mem_fun (*_rc_config, &RCConfiguration::get_default_narrow_ms),
793                      mem_fun (*_rc_config, &RCConfiguration::set_default_narrow_ms)
794                      ));
795
796         add (_("Misc"),
797              new BoolOption (
798                      "name-new-markers",
799                      _("Name new markers"),
800                      mem_fun (*_rc_config, &RCConfiguration::get_name_new_markers),
801                      mem_fun (*_rc_config, &RCConfiguration::set_name_new_markers)
802                      ));
803
804         /* TRANSPORT */
805
806         add (_("Transport"),
807              new BoolOption (
808                      "latched-record-enable",
809                      _("Keep record-enable engaged on stop"),
810                      mem_fun (*_rc_config, &RCConfiguration::get_latched_record_enable),
811                      mem_fun (*_rc_config, &RCConfiguration::set_latched_record_enable)
812                      ));
813
814         add (_("Transport"),
815              new BoolOption (
816                      "stop-recording-on-xrun",
817                      _("Stop recording when an xrun occurs"),
818                      mem_fun (*_rc_config, &RCConfiguration::get_stop_recording_on_xrun),
819                      mem_fun (*_rc_config, &RCConfiguration::set_stop_recording_on_xrun)
820                      ));
821
822         add (_("Transport"),
823              new BoolOption (
824                      "create-xrun-marker",
825                      _("Create markers where xruns occur"),
826                      mem_fun (*_rc_config, &RCConfiguration::get_create_xrun_marker),
827                      mem_fun (*_rc_config, &RCConfiguration::set_create_xrun_marker)
828                      ));
829
830         add (_("Transport"),
831              new BoolOption (
832                      "quieten-at-speed",
833                      _("Reduce output level by 12dB during fast forward / rewind"),
834                      mem_fun (*_rc_config, &RCConfiguration::get_quieten_at_speed),
835                      mem_fun (*_rc_config, &RCConfiguration::set_quieten_at_speed)
836                      ));
837
838         add (_("Transport"),
839              new BoolOption (
840                      "stop-at-session-end",
841                      _("Stop at the end of the session"),
842                      mem_fun (*_rc_config, &RCConfiguration::get_stop_at_session_end),
843                      mem_fun (*_rc_config, &RCConfiguration::set_stop_at_session_end)
844                      ));
845
846         add (_("Transport"),
847              new BoolOption (
848                      "primary-clock-delta-edit-cursor",
849                      _("Primary clock delta to edit cursor"),
850                      mem_fun (*_rc_config, &RCConfiguration::get_primary_clock_delta_edit_cursor),
851                      mem_fun (*_rc_config, &RCConfiguration::set_primary_clock_delta_edit_cursor)
852                      ));
853
854         add (_("Transport"),
855              new BoolOption (
856                      "secondary-clock-delta-edit-cursor",
857                      _("Secondary clock delta to edit cursor"),
858                      mem_fun (*_rc_config, &RCConfiguration::get_secondary_clock_delta_edit_cursor),
859                      mem_fun (*_rc_config, &RCConfiguration::set_secondary_clock_delta_edit_cursor)
860                      ));
861
862         /* EDITOR */
863
864         add (_("Editor"),
865              new BoolOption (
866                      "link-region-and-track-selection",
867                      _("Link selection of regions and tracks"),
868                      mem_fun (*_rc_config, &RCConfiguration::get_link_region_and_track_selection),
869                      mem_fun (*_rc_config, &RCConfiguration::set_link_region_and_track_selection)
870                      ));
871
872         add (_("Editor"),
873              new BoolOption (
874                      "automation-follows-regions",
875                      _("Move relevant automation when regions are moved"),
876                      mem_fun (*_rc_config, &RCConfiguration::get_automation_follows_regions),
877                      mem_fun (*_rc_config, &RCConfiguration::set_automation_follows_regions)
878                      ));
879
880         add (_("Editor"),
881              new BoolOption (
882                      "show-track-meters",
883                      _("Show meters on tracks in the editor"),
884                      mem_fun (*_rc_config, &RCConfiguration::get_show_track_meters),
885                      mem_fun (*_rc_config, &RCConfiguration::set_show_track_meters)
886                      ));
887
888         add (_("Editor"),
889              new BoolOption (
890                      "use-overlap-equivalency",
891                      _("Use overlap equivalency for regions"),
892                      mem_fun (*_rc_config, &RCConfiguration::get_use_overlap_equivalency),
893                      mem_fun (*_rc_config, &RCConfiguration::set_use_overlap_equivalency)
894                      ));
895
896         add (_("Editor"),
897              new BoolOption (
898                      "rubberbanding-snaps-to-grid",
899                      _("Make rubberband selection rectangle snap to the grid"),
900                      mem_fun (*_rc_config, &RCConfiguration::get_rubberbanding_snaps_to_grid),
901                      mem_fun (*_rc_config, &RCConfiguration::set_rubberbanding_snaps_to_grid)
902                      ));
903
904         /* AUDIO */
905
906         add (_("Audio"), new OptionEditorHeading (_("Solo")));
907
908         ComboOption<SoloModel>* sm = new ComboOption<SoloModel> (
909                 "solo-model",
910                 _("Solo"),
911                 mem_fun (*_rc_config, &RCConfiguration::get_solo_model),
912                 mem_fun (*_rc_config, &RCConfiguration::set_solo_model)
913                 );
914
915         sm->add (InverseMute, _("in place"));
916         sm->add (SoloBus, _("via bus"));
917
918         add (_("Audio"), sm);
919
920         add (_("Audio"),
921              new BoolOption (
922                      "solo-latched",
923                      _("Latched solo"),
924                      mem_fun (*_rc_config, &RCConfiguration::get_solo_latched),
925                      mem_fun (*_rc_config, &RCConfiguration::set_solo_latched)
926                      ));
927
928         add (_("Audio"),
929              new BoolOption (
930                      "show-solo-mutes",
931                      _("Show solo muting"),
932                      mem_fun (*_rc_config, &RCConfiguration::get_show_solo_mutes),
933                      mem_fun (*_rc_config, &RCConfiguration::set_show_solo_mutes)
934                      ));
935
936         add (_("Audio"),
937              new BoolOption (
938                      "solo-mute-override",
939                      _("Override muting"),
940                      mem_fun (*_rc_config, &RCConfiguration::get_solo_mute_override),
941                      mem_fun (*_rc_config, &RCConfiguration::set_solo_mute_override)
942                      ));
943
944         add (_("Audio"), new OptionEditorHeading (_("Monitoring")));
945
946         ComboOption<MonitorModel>* mm = new ComboOption<MonitorModel> (
947                 "monitoring-model",
948                 _("Monitoring handled by"),
949                 mem_fun (*_rc_config, &RCConfiguration::get_monitoring_model),
950                 mem_fun (*_rc_config, &RCConfiguration::set_monitoring_model)
951                 );
952
953         mm->add (HardwareMonitoring, _("JACK"));
954         mm->add (SoftwareMonitoring, _("ardour"));
955         mm->add (ExternalMonitoring, _("audio hardware"));
956
957         add (_("Audio"), mm);
958
959         add (_("Audio"),
960              new BoolOption (
961                      "tape-machine-mode",
962                      _("Tape machine mode"),
963                      mem_fun (*_rc_config, &RCConfiguration::get_tape_machine_mode),
964                      mem_fun (*_rc_config, &RCConfiguration::set_tape_machine_mode)
965                      ));
966
967         add (_("Audio"), new OptionEditorHeading (_("Connection of tracks and busses")));
968
969         ComboOption<AutoConnectOption>* iac = new ComboOption<AutoConnectOption> (
970                 "input-auto-connect",
971                 _("Connect track and bus inputs"),
972                 mem_fun (*_rc_config, &RCConfiguration::get_input_auto_connect),
973                 mem_fun (*_rc_config, &RCConfiguration::set_input_auto_connect)
974                 );
975
976         iac->add (AutoConnectPhysical, _("automatically to physical inputs"));
977         iac->add (ManualConnect, _("manually"));
978
979         add (_("Audio"), iac);
980
981         ComboOption<AutoConnectOption>* oac = new ComboOption<AutoConnectOption> (
982                 "output-auto-connect",
983                 _("Connect track and bus outputs"),
984                 mem_fun (*_rc_config, &RCConfiguration::get_output_auto_connect),
985                 mem_fun (*_rc_config, &RCConfiguration::set_output_auto_connect)
986                 );
987
988         oac->add (AutoConnectPhysical, _("automatically to physical outputs"));
989         oac->add (AutoConnectMaster, _("automatically to master outputs"));
990         oac->add (ManualConnect, _("manually"));
991
992         add (_("Audio"), oac);
993
994         add (_("Audio"), new OptionEditorHeading (_("Denormals")));
995
996         add (_("Audio"),
997              new BoolOption (
998                      "denormal-protection",
999                      _("Use DC bias to protect against denormals"),
1000                      mem_fun (*_rc_config, &RCConfiguration::get_denormal_protection),
1001                      mem_fun (*_rc_config, &RCConfiguration::set_denormal_protection)
1002                      ));
1003
1004         ComboOption<DenormalModel>* dm = new ComboOption<DenormalModel> (
1005                 "denormal-model",
1006                 _("Processor handling"),
1007                 mem_fun (*_rc_config, &RCConfiguration::get_denormal_model),
1008                 mem_fun (*_rc_config, &RCConfiguration::set_denormal_model)
1009                 );
1010         
1011         dm->add (DenormalNone, _("no processor handling"));
1012         
1013         FPU fpu;
1014         
1015         if (fpu.has_flush_to_zero()) {
1016                 dm->add (DenormalFTZ, _("use FlushToZero"));
1017         }
1018         
1019         if (fpu.has_denormals_are_zero()) {
1020                 dm->add (DenormalDAZ, _("use DenormalsAreZero"));
1021         }
1022         
1023         if (fpu.has_flush_to_zero() && fpu.has_denormals_are_zero()) {
1024                 dm->add (DenormalFTZDAZ, _("use FlushToZero and DenormalsAreZerO"));
1025         }
1026         
1027         add (_("Audio"), dm);
1028
1029         add (_("Audio"), new OptionEditorHeading (_("Plugins")));
1030
1031         add (_("Audio"),
1032              new BoolOption (
1033                      "plugins-stop-with-transport",
1034                      _("Stop plugins when the transport is stopped"),
1035                      mem_fun (*_rc_config, &RCConfiguration::get_plugins_stop_with_transport),
1036                      mem_fun (*_rc_config, &RCConfiguration::set_plugins_stop_with_transport)
1037                      ));
1038
1039         add (_("Audio"),
1040              new BoolOption (
1041                      "do-not-record-plugins",
1042                      _("Disable plugins during recording"),
1043                      mem_fun (*_rc_config, &RCConfiguration::get_do_not_record_plugins),
1044                      mem_fun (*_rc_config, &RCConfiguration::set_do_not_record_plugins)
1045                      ));
1046
1047         add (_("Audio"),
1048              new BoolOption (
1049                      "new-plugins-active",
1050                      _("Make new plugins active"),
1051                      mem_fun (*_rc_config, &RCConfiguration::get_new_plugins_active),
1052                      mem_fun (*_rc_config, &RCConfiguration::set_new_plugins_active)
1053                      ));
1054
1055         add (_("Audio"),
1056              new BoolOption (
1057                      "auto-analyse-audio",
1058                      _("Enable automatic analysis of audio"),
1059                      mem_fun (*_rc_config, &RCConfiguration::get_auto_analyse_audio),
1060                      mem_fun (*_rc_config, &RCConfiguration::set_auto_analyse_audio)
1061                      ));
1062
1063         /* MIDI CONTROL */
1064
1065         add (_("MIDI control"), new MIDIPorts (_rc_config));
1066
1067         add (_("MIDI control"),
1068              new SpinOption<uint8_t> (
1069                      "mmc-receive-device-id",
1070                      _("Inbound MMC device ID"),
1071                      mem_fun (*_rc_config, &RCConfiguration::get_mmc_receive_device_id),
1072                      mem_fun (*_rc_config, &RCConfiguration::set_mmc_receive_device_id),
1073                      0, 128, 1, 10
1074                      ));
1075
1076         add (_("MIDI control"),
1077              new SpinOption<uint8_t> (
1078                      "mmc-send-device-id",
1079                      _("Outbound MMC device ID"),
1080                      mem_fun (*_rc_config, &RCConfiguration::get_mmc_send_device_id),
1081                      mem_fun (*_rc_config, &RCConfiguration::set_mmc_send_device_id),
1082                      0, 128, 1, 10
1083                      ));
1084
1085         add (_("MIDI control"),
1086              new SpinOption<int32_t> (
1087                      "initial-program-change",
1088                      _("Initial program change"),
1089                      mem_fun (*_rc_config, &RCConfiguration::get_initial_program_change),
1090                      mem_fun (*_rc_config, &RCConfiguration::set_initial_program_change),
1091                      -1, 65536, 1, 10
1092                      ));
1093
1094         /* CLICK */
1095
1096         add (_("Click"), new ClickOptions (_rc_config, this));
1097
1098         /* KEYBOARD */
1099
1100         add (_("Keyboard"), new KeyboardOptions);
1101 }
1102
1103