Uploaded start of CoreAudioSource. More sfdb work.
[ardour.git] / gtk2_ardour / option_editor.cc
1 /*
2     Copyright (C) 2001 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #include <ardour/session.h>
22 #include <ardour/audioengine.h>
23 #include <ardour/configuration.h>
24 #include <ardour/auditioner.h>
25 #include <ardour/crossfade.h>
26 #include <midi++/manager.h>
27 #include <gtkmm2ext/stop_signal.h>
28 #include <gtkmm2ext/utils.h>
29
30 #include "public_editor.h"
31 #include "mixer_ui.h"
32 #include "ardour_ui.h"
33 #include "io_selector.h"
34 #include "gain_meter.h"
35 #include "sfdb_ui.h"
36 #include "utils.h"
37 #include "editing.h"
38 #include "option_editor.h"
39
40 #include "i18n.h"
41
42 using namespace ARDOUR;
43 using namespace Gtk;
44 using namespace Editing;
45 using namespace Gtkmm2ext;
46 using namespace std;
47
48 static const gchar *psync_strings[] = {
49         N_("Internal"),
50         N_("Slave to MTC"),
51         N_("Sync with JACK"),
52         N_("never used but stops crashes"),
53         0
54 };
55
56 static const gchar *lmode_strings[] = {
57         N_("Later regions are higher"),
58         N_("Most recently added/moved/trimmed regions are higher"),
59         N_("Most recently added regions are higher"),
60         0
61 };
62
63 static const gchar *xfl_strings[] = {
64         N_("Span entire region overlap"),
65         N_("Short fades at the start of the overlap"),
66         0
67 };
68
69 static vector<string> positional_sync_strings;
70 static vector<string> layer_mode_strings;
71 static vector<string> xfade_model_strings;
72
73 OptionEditor::OptionEditor (ARDOUR_UI& uip, PublicEditor& ed, Mixer_UI& mixui)
74         : Dialog ("option editor"),
75           ui (uip),
76           editor (ed),
77           mixer (mixui),
78
79           /* Paths */
80           path_table (11, 2),
81           sfdb_paths(ListStore::create(sfdb_path_columns)),
82           sfdb_path_view(sfdb_paths),
83
84           /* Fades */
85
86           auto_xfade_button (_("Automatically create crossfades")),
87           xfade_active_button (_("New full-overlap crossfades are unmuted")),
88           layer_mode_label (_("Region layering mode")),
89           xfade_model_label (_("Crossfade model")),
90           short_xfade_adjustment (0, 1.0, 500.0, 5.0, 100.0),
91           short_xfade_slider (short_xfade_adjustment),
92
93           /* solo */
94           solo_latched_button (_("Latched solo")),
95           solo_via_bus_button (_("Solo via bus")),
96
97           /* display */
98
99           show_waveforms_button (_("Show waveforms")),
100           show_waveforms_recording_button (_("Show waveforms while recording")),
101           mixer_strip_width_button (_("Narrow mixer strips")),
102           show_measures_button (_("Show measure lines")),
103           follow_playhead_button (_("Follow playhead")),
104           
105           /* Sync */
106
107           send_mtc_button (_("Send MTC")),
108           send_mmc_button (_("Send MMC")),
109           jack_time_master_button (_("JACK time master")),
110           smpte_offset_clock (X_("SMPTEOffsetClock"), true, true),
111           smpte_offset_negative_button (_("SMPTE offset is negative")),
112
113           /* MIDI */
114
115           midi_feedback_button (_("Send MIDI parameter feedback")),
116           midi_control_button (_("MIDI parameter control")),
117           mmc_control_button (_("MMC control")),
118           
119           /* Click */
120
121           click_table (2, 3),
122           click_browse_button (_("Browse")),
123           click_emphasis_browse_button (_("Browse")),
124
125           /* kbd/mouse */
126
127           keyboard_mouse_table (3, 4),
128           delete_button_adjustment (3, 1, 5),
129           delete_button_spin (delete_button_adjustment),
130           edit_button_adjustment (3, 1, 5),
131           edit_button_spin (edit_button_adjustment),
132
133           /* Misc */
134
135           auto_connect_inputs_button (_("Auto-connect new track inputs to hardware")),
136           auto_connect_output_physical_button (_("Auto-connect new track outputs to hardware")),
137           auto_connect_output_master_button (_("Auto-connect new track outputs to master bus")),
138           auto_connect_output_manual_button (_("Manually connect new track outputs")),
139           hw_monitor_button(_("Use Hardware Monitoring")),
140           sw_monitor_button(_("Use Software Monitoring")),
141           plugins_stop_button (_("Stop plugins with transport")),
142           plugins_on_rec_button (_("Run plugins while recording")),
143           verify_remove_last_capture_button (_("Verify remove last capture")),
144           stop_rec_on_xrun_button (_("Stop recording on xrun")),
145           stop_at_end_button (_("Stop transport at end of session")),
146           debug_keyboard_button (_("Debug keyboard events")),
147           speed_quieten_button (_("-12dB gain reduction for ffwd/rew"))
148           
149 {
150         using namespace Notebook_Helpers;
151
152         click_io_selector = 0;
153         auditioner_io_selector = 0;
154
155         set_default_size (300, 300);
156         set_title (_("ardour: options editor"));
157         set_wmclass (_("ardour_option_editor"), "Ardour");
158
159         set_name ("OptionsWindow");
160         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
161         
162         layer_mode_label.set_name ("OptionsLabel");
163         xfade_model_label.set_name ("OptionsLabel");
164         
165         VBox *vbox = get_vbox();
166         set_border_width (3);
167
168         vbox->set_spacing (4);
169         vbox->pack_start(notebook);
170
171         signal_delete_event().connect (mem_fun(*this, &OptionEditor::wm_close));
172
173         notebook.set_show_tabs (true);
174         notebook.set_show_border (true);
175         notebook.set_name ("OptionsNotebook");
176
177         setup_sync_options();
178         setup_path_options();
179         setup_fade_options ();
180         setup_solo_options ();
181         setup_display_options ();
182         setup_misc_options ();
183         setup_keyboard_options ();
184         setup_auditioner_editor ();
185
186         notebook.pages().push_back (TabElem (misc_packer, _("Misc")));
187         notebook.pages().push_back (TabElem (sync_packer, _("Sync")));
188         notebook.pages().push_back (TabElem (path_table, _("Paths/Files")));
189         notebook.pages().push_back (TabElem (display_packer, _("Display")));
190         notebook.pages().push_back (TabElem (keyboard_mouse_table, _("Kbd/Mouse")));
191         notebook.pages().push_back (TabElem (click_packer, _("Click")));
192         notebook.pages().push_back (TabElem (audition_packer, _("Audition")));
193         notebook.pages().push_back (TabElem (fade_packer, _("Layers & Fades")));
194         notebook.pages().push_back (TabElem (solo_packer, _("Solo")));
195
196         if (!MIDI::Manager::instance()->get_midi_ports().empty()) {
197                 setup_midi_options ();
198                 notebook.pages().push_back (TabElem (midi_packer, _("MIDI")));
199         }
200
201         set_session (0);
202         show_all_children();
203 }
204
205 void
206 OptionEditor::set_session (Session *s)
207 {
208         clear_click_editor ();
209         clear_auditioner_editor ();
210
211         click_path_entry.set_text ("");
212         click_emphasis_path_entry.set_text ("");
213         session_raid_entry.set_text ("");
214
215         send_mtc_button.set_sensitive (false);
216         send_mmc_button.set_sensitive (false);
217         midi_feedback_button.set_sensitive (false);
218         midi_control_button.set_sensitive (false);
219         mmc_control_button.set_sensitive (false);
220         click_path_entry.set_sensitive (false);
221         click_emphasis_path_entry.set_sensitive (false);
222         session_raid_entry.set_sensitive (false);
223         plugins_on_rec_button.set_sensitive (false);
224         verify_remove_last_capture_button.set_sensitive (false);
225         slave_type_combo.set_sensitive (false);
226         solo_latched_button.set_sensitive (false);
227         solo_via_bus_button.set_sensitive (false);
228         smpte_fps_combo.set_sensitive (false);
229         meter_hold_combo.set_sensitive (false);
230         meter_falloff_combo.set_sensitive (false);
231         auto_connect_inputs_button.set_sensitive (false);
232         auto_connect_output_physical_button.set_sensitive (false);
233         auto_connect_output_master_button.set_sensitive (false);
234         auto_connect_output_manual_button.set_sensitive (false);
235         layer_mode_combo.set_sensitive (false);
236         short_xfade_slider.set_sensitive (false);
237         smpte_offset_negative_button.set_sensitive (false);
238
239         smpte_offset_clock.set_session (s);
240
241         if ((session = s) == 0) {
242                 return;
243         }
244
245         send_mtc_button.set_sensitive (true);
246         send_mmc_button.set_sensitive (true);
247         midi_feedback_button.set_sensitive (true);
248         midi_control_button.set_sensitive (true);
249         mmc_control_button.set_sensitive (true);
250         click_path_entry.set_sensitive (true);
251         click_emphasis_path_entry.set_sensitive (true);
252         session_raid_entry.set_sensitive (true);
253         plugins_on_rec_button.set_sensitive (true);
254         verify_remove_last_capture_button.set_sensitive (true);
255         slave_type_combo.set_sensitive (true);
256         solo_latched_button.set_sensitive (true);
257         solo_via_bus_button.set_sensitive (true);
258         smpte_fps_combo.set_sensitive (true);
259         meter_hold_combo.set_sensitive (true);
260         meter_falloff_combo.set_sensitive (true);
261         auto_connect_inputs_button.set_sensitive (true);
262         auto_connect_output_physical_button.set_sensitive (true);
263         auto_connect_output_master_button.set_sensitive (true);
264         auto_connect_output_manual_button.set_sensitive (true);
265         layer_mode_combo.set_sensitive (true);
266         short_xfade_slider.set_sensitive (true);
267         smpte_offset_negative_button.set_sensitive (true);
268
269         if (!s->smpte_drop_frames) {
270                 // non-drop frames
271                 if (s->smpte_frames_per_second == 24.0)
272                         smpte_fps_combo.set_active_text (_("24 FPS"));
273                 else if (s->smpte_frames_per_second == 25.0)
274                         smpte_fps_combo.set_active_text (_("25 FPS"));
275                 else if (s->smpte_frames_per_second == 30.0)
276                         smpte_fps_combo.set_active_text (_("30 FPS"));
277                 else
278                         smpte_fps_combo.set_active_text (_("???"));
279         } else {
280                 // drop frames
281                 if (floor(s->smpte_frames_per_second) == 29.0)
282                         smpte_fps_combo.set_active_text (_("30 FPS drop"));
283                 else
284                         smpte_fps_combo.set_active_text (_("???"));
285         }
286         
287         smpte_offset_clock.set_session (s);
288         smpte_offset_clock.set (s->smpte_offset (), true);
289
290         smpte_offset_negative_button.set_active (session->smpte_offset_negative());
291         send_mtc_button.set_active (session->get_send_mtc());
292
293         /* MIDI I/O */
294
295         send_mmc_button.set_active (session->get_send_mmc());
296         midi_control_button.set_active (session->get_midi_control());
297         midi_feedback_button.set_active (session->get_midi_feedback());
298         mmc_control_button.set_active (session->get_mmc_control());
299
300         /* set up port assignments */
301
302         std::map<MIDI::Port*,vector<RadioButton*> >::iterator res;
303
304         if (session->mtc_port()) {
305                 if ((res = port_toggle_buttons.find (session->mtc_port())) != port_toggle_buttons.end()) {
306                         (*res).second[MtcIndex]->set_active (true);
307                 }
308         } 
309
310         if (session->mmc_port ()) {
311                 if ((res = port_toggle_buttons.find (session->mmc_port())) != port_toggle_buttons.end()) {
312                         (*res).second[MmcIndex]->set_active (true);
313                 } 
314         }
315
316         if (session->midi_port()) {
317                 if ((res = port_toggle_buttons.find (session->midi_port())) != port_toggle_buttons.end()) {
318                         (*res).second[MidiIndex]->set_active (true);
319                 }
320         }
321
322         auto_connect_inputs_button.set_active (session->get_input_auto_connect());
323
324         Session::AutoConnectOption oac = session->get_output_auto_connect();
325         if (oac & Session::AutoConnectPhysical) {
326                 auto_connect_output_physical_button.set_active (true);
327         } else if (oac & Session::AutoConnectMaster) {
328                 auto_connect_output_master_button.set_active (true);
329         } else {
330                 auto_connect_output_manual_button.set_active (true);
331         }
332
333         setup_click_editor ();
334         connect_audition_editor ();
335
336         plugins_on_rec_button.set_active (session->get_recording_plugins ());
337         verify_remove_last_capture_button.set_active (Config->get_verify_remove_last_capture());
338
339         layer_mode_combo.set_active_text (layer_mode_strings[session->get_layer_model()]);
340         xfade_model_combo.set_active_text (xfade_model_strings[session->get_xfade_model()]);
341
342         short_xfade_adjustment.set_value ((Crossfade::short_xfade_length() / (float) session->frame_rate()) * 1000.0);
343
344         xfade_active_button.set_active (session->get_crossfades_active());
345         solo_latched_button.set_active (session->solo_latched());
346         solo_via_bus_button.set_active (session->solo_model() == Session::SoloBus);
347         
348         add_session_paths ();
349
350         vector<string> dumb;
351         dumb.push_back (positional_sync_strings[Session::None]);
352         dumb.push_back (positional_sync_strings[Session::JACK]);
353         if (session->mtc_port()) {
354                 dumb.push_back (positional_sync_strings[Session::MTC]);
355         } 
356         set_popdown_strings (slave_type_combo, dumb);
357
358         // meter stuff
359         if (session->meter_falloff() == 0.0f) {
360                 meter_falloff_combo.set_active_text (_("Off"));
361         } else if (session->meter_falloff() <= 0.3f) {
362                 meter_falloff_combo.set_active_text (_("Slowest"));
363         } else if (session->meter_falloff() <= 0.4f) {
364                 meter_falloff_combo.set_active_text (_("Slow"));
365         } else if (session->meter_falloff() <= 0.8f) {
366                 meter_falloff_combo.set_active_text (_("Medium"));
367         } else if (session->meter_falloff() <= 1.4f) {
368                 meter_falloff_combo.set_active_text (_("Fast"));
369         } else if (session->meter_falloff() <= 2.0f) {
370                 meter_falloff_combo.set_active_text (_("Faster"));
371         } else {
372                 meter_falloff_combo.set_active_text (_("Fastest"));
373         }
374
375         switch ((int) floor (session->meter_hold())) {
376         case 0:
377                 meter_hold_combo.set_active_text (_("Off"));
378                 break;
379         case 40:
380                 meter_hold_combo.set_active_text (_("Short"));
381                 break;
382         case 100:
383                 meter_hold_combo.set_active_text (_("Medium"));
384                 break;
385         case 200:
386                 meter_hold_combo.set_active_text (_("Long"));
387                 break;
388         }
389         
390         session_control_changed (Session::SlaveType);
391         session_control_changed (Session::AlignChoice);
392         session->ControlChanged.connect (mem_fun(*this, &OptionEditor::queue_session_control_changed));
393 }
394
395 OptionEditor::~OptionEditor ()
396 {
397 }
398
399 static const gchar *native_format_strings[] = {
400         N_("Broadcast WAVE/floating point"),
401         N_("WAVE/floating point"),
402         0
403 };
404
405 void
406 OptionEditor::setup_path_options()
407 {
408         Gtk::Label* label;
409
410         path_table.set_homogeneous (true);
411         path_table.set_border_width (12);
412         path_table.set_row_spacings (5);
413
414         session_raid_entry.set_name ("OptionsEntry");
415
416         session_raid_entry.signal_activate().connect (mem_fun(*this, &OptionEditor::raid_path_changed));
417
418         label = manage(new Label(_("session RAID path")));
419         label->set_name ("OptionsLabel");
420         path_table.attach (*label, 0, 1, 0, 1, FILL|EXPAND, FILL);
421         path_table.attach (session_raid_entry, 1, 3, 0, 1, Gtk::FILL|Gtk::EXPAND, FILL);
422
423         label = manage(new Label(_("Native Format")));
424         label->set_name ("OptionsLabel");
425         path_table.attach (*label, 0, 1, 1, 2, FILL|EXPAND, FILL);
426         path_table.attach (native_format_combo, 1, 3, 1, 2, Gtk::FILL|Gtk::EXPAND, FILL);
427
428         label = manage(new Label(_("Soundfile Search Paths")));
429         label->set_name("OptionsLabel");
430         path_table.attach(*label, 0, 1, 2, 3, FILL|EXPAND, FILL);
431         path_table.attach(sfdb_path_view, 1, 3, 2, 3, Gtk::FILL|Gtk::EXPAND, FILL);
432
433         sfdb_path_view.append_column(_("Paths"), sfdb_path_columns.paths);
434
435         vector<string> nfstrings = internationalize (native_format_strings);
436
437         set_popdown_strings (native_format_combo, nfstrings);
438         native_format_combo.signal_changed().connect (mem_fun(*this, &OptionEditor::native_format_chosen));
439
440         fixup_combo_size (native_format_combo, nfstrings);
441
442         if (Config->get_native_format_is_bwf()) {
443                 native_format_combo.set_active_text (native_format_strings[0]);
444         } else {
445                 native_format_combo.set_active_text (native_format_strings[1]);
446         }
447         
448         path_table.show_all();
449 }
450
451 void
452 OptionEditor::add_session_paths ()
453 {
454         click_path_entry.set_sensitive (true);
455         click_emphasis_path_entry.set_sensitive (true);
456         session_raid_entry.set_sensitive (true);
457
458         if (session->click_sound.length() == 0) {
459                 click_path_entry.set_text (_("internal"));
460         } else {
461                 click_path_entry.set_text (session->click_sound);
462         }
463
464         if (session->click_emphasis_sound.length() == 0) {
465                 click_emphasis_path_entry.set_text (_("internal"));
466         } else {
467                 click_emphasis_path_entry.set_text (session->click_emphasis_sound);
468         }
469
470         session_raid_entry.set_text(session->raid_path());
471 }
472
473 void
474 OptionEditor::setup_fade_options ()
475 {
476         Gtk::HBox* hbox;
477         vector<string> dumb;
478         
479         auto_xfade_button.set_name ("OptionEditorToggleButton");
480         xfade_active_button.set_name ("OptionEditorToggleButton");
481
482         hbox = manage (new HBox);
483         hbox->set_border_width (12);
484         hbox->pack_start (auto_xfade_button, false, false);
485         fade_packer.pack_start (*hbox, false, false);
486
487         hbox = manage (new HBox);
488         hbox->set_border_width (12);
489         hbox->pack_start (xfade_active_button, false, false);
490         fade_packer.pack_start (*hbox, false, false);
491
492         layer_mode_strings = internationalize (lmode_strings);
493
494         dumb.push_back (lmode_strings[Session::LaterHigher]);
495         dumb.push_back (lmode_strings[Session::MoveAddHigher]);
496         dumb.push_back (lmode_strings[Session::AddHigher]);
497         set_popdown_strings (layer_mode_combo, dumb);
498
499         layer_mode_combo.signal_changed ().connect (mem_fun(*this, &OptionEditor::layer_mode_chosen));
500
501         fixup_combo_size (layer_mode_combo, layer_mode_strings);
502
503         hbox = manage (new HBox);
504         hbox->set_border_width (5);
505         hbox->set_spacing (10);
506         hbox->pack_start (layer_mode_label, false, false);
507         hbox->pack_start (layer_mode_combo, false, false);
508         fade_packer.pack_start (*hbox, false, false);
509
510         xfade_model_strings = internationalize (xfl_strings);
511
512         dumb.clear ();
513         dumb.push_back (xfade_model_strings[FullCrossfade]);
514         dumb.push_back (xfade_model_strings[ShortCrossfade]);
515         set_popdown_strings (xfade_model_combo, dumb);
516
517         xfade_model_combo.signal_changed().connect (mem_fun(*this, &OptionEditor::xfade_model_chosen));
518
519         fixup_combo_size (xfade_model_combo, xfade_model_strings);
520
521         hbox = manage (new HBox);
522         hbox->set_border_width (5);
523         hbox->set_spacing (10);
524         hbox->pack_start (xfade_model_label, false, false);
525         hbox->pack_start (xfade_model_combo, false, false);
526         fade_packer.pack_start (*hbox, false, false);
527
528         auto_xfade_button.set_active (Config->get_auto_xfade());
529         /* xfade and layer mode active requires session */
530
531         auto_xfade_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::auto_xfade_clicked));
532         xfade_active_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::xfade_active_clicked));
533         
534         Label* short_xfade_label = manage (new Label (_("Short crossfade length (msecs)")));
535         short_xfade_label->set_name ("OptionsLabel");
536         
537         hbox = manage (new HBox);
538         hbox->set_border_width (5);
539         hbox->set_spacing (10);
540         hbox->pack_start (*short_xfade_label, false, false);
541         hbox->pack_start (short_xfade_slider, true, true);
542         fade_packer.pack_start (*hbox, false, false);
543
544         short_xfade_adjustment.signal_value_changed().connect (mem_fun(*this, &OptionEditor::short_xfade_adjustment_changed));
545
546         fade_packer.show_all ();
547 }
548
549 void
550 OptionEditor::short_xfade_adjustment_changed ()
551 {
552         if (session) {
553                 float val = short_xfade_adjustment.get_value();
554                 
555                 /* val is in msecs */
556                 
557                 Crossfade::set_short_xfade_length ((jack_nframes_t) floor (session->frame_rate() * (val / 1000.0)));
558         }
559 }
560
561 void
562 OptionEditor::layer_mode_chosen ()
563 {
564         if (!session) {
565                 return;
566         }
567
568         string which = layer_mode_combo.get_active_text ();
569
570         if (which == layer_mode_strings[Session::LaterHigher]) {
571                 session->set_layer_model (Session::LaterHigher);
572         } else if (which == layer_mode_strings[Session::MoveAddHigher]) {
573                 session->set_layer_model (Session::MoveAddHigher);
574         } else if (which == layer_mode_strings[Session::AddHigher]) {
575                 session->set_layer_model (Session::AddHigher);
576         }
577 }
578
579 void
580 OptionEditor::xfade_model_chosen ()
581 {
582         if (!session) {
583                 return;
584         }
585
586         string which = xfade_model_combo.get_active_text ();
587
588         if (which == xfade_model_strings[FullCrossfade]) {
589                 session->set_xfade_model (FullCrossfade);
590         } else if (which == xfade_model_strings[ShortCrossfade]) {
591                 session->set_xfade_model (ShortCrossfade);
592         }
593 }
594
595 void
596 OptionEditor::auto_xfade_clicked ()
597 {
598         Config->set_auto_xfade (auto_xfade_button.get_active());
599 }
600
601 void
602 OptionEditor::xfade_active_clicked ()
603 {
604         if (session) {
605                 session->set_crossfades_active (xfade_active_button.get_active());
606         }
607 }
608
609 void
610 OptionEditor::setup_solo_options ()
611 {
612         Gtk::HBox* hbox;
613
614         solo_via_bus_button.set_name ("OptionEditorToggleButton");
615         solo_latched_button.set_name ("OptionEditorToggleButton");
616
617         hbox = manage (new HBox);
618         hbox->set_border_width (12);
619         hbox->pack_start (solo_via_bus_button, false, false);
620         solo_packer.pack_start (*hbox, false, false);
621
622         hbox = manage (new HBox);
623         hbox->set_border_width (12);
624         hbox->pack_start (solo_latched_button, false, false);
625         solo_packer.pack_start (*hbox, false, false);
626
627         solo_via_bus_button.signal_clicked().connect 
628                 (mem_fun(*this, &OptionEditor::solo_via_bus_clicked));
629         solo_latched_button.signal_clicked().connect 
630                 (mem_fun(*this, &OptionEditor::solo_latched_clicked));
631
632         solo_packer.show_all ();
633 }
634
635 void
636 OptionEditor::solo_via_bus_clicked ()
637 {
638         if (!session) {
639                 return;
640         }
641
642         if (solo_via_bus_button.get_active()) {
643                 session->set_solo_model (Session::SoloBus);
644         } else {
645                 session->set_solo_model (Session::InverseMute);
646         }
647 }
648
649 void
650 OptionEditor::solo_latched_clicked ()
651 {
652         if (!session) {
653                 return;
654         }
655
656         bool x = solo_latched_button.get_active();
657
658         if (x != session->solo_latched()) {
659                 session->set_solo_latched (x);
660         }
661 }
662
663 void
664 OptionEditor::setup_display_options ()
665 {
666         HBox* hbox;
667         vector<string> dumb;
668
669         display_packer.set_border_width (12);
670         display_packer.set_spacing (5);
671
672         show_waveforms_button.set_name ("OptionEditorToggleButton");
673         show_waveforms_recording_button.set_name ("OptionEditorToggleButton");
674         show_measures_button.set_name ("OptionEditorToggleButton");
675         follow_playhead_button.set_name ("OptionEditorToggleButton");
676         mixer_strip_width_button.set_name ("OptionEditorToggleButton");
677
678         mixer_strip_width_button.set_active (mixer.get_strip_width() == Narrow);
679
680         hbox = manage (new HBox);
681         hbox->set_border_width (8);
682         hbox->pack_start (show_waveforms_button, false, false);
683         display_packer.pack_start (*hbox, false, false);
684
685         hbox = manage (new HBox);
686         hbox->set_border_width (8);
687         hbox->pack_start (show_waveforms_recording_button, false, false);
688         display_packer.pack_start (*hbox, false, false);
689         
690         hbox = manage (new HBox);
691         hbox->set_border_width (8);
692         hbox->pack_start (show_measures_button, false, false);
693         display_packer.pack_start (*hbox, false, false);
694
695         hbox = manage (new HBox);
696         hbox->set_border_width (8);
697         hbox->pack_start (mixer_strip_width_button, false, false);
698         display_packer.pack_start (*hbox, false, false);
699
700         hbox = manage (new HBox);
701         hbox->set_border_width (8);
702         hbox->pack_start (follow_playhead_button, false, false);
703         display_packer.pack_start (*hbox, false, false);
704
705         Label *meter_hold_label = manage (new Label (_("Meter Peak Hold")));
706         meter_hold_label->set_name ("OptionsLabel");
707         dumb.clear ();
708         dumb.push_back (_("Off"));
709         dumb.push_back (_("Short"));
710         dumb.push_back (_("Medium"));
711         dumb.push_back (_("Long"));
712         set_popdown_strings (meter_hold_combo, dumb);
713         meter_hold_combo.signal_changed().connect (mem_fun(*this, &OptionEditor::meter_hold_chosen));
714         hbox = manage (new HBox);
715         hbox->set_border_width (8);
716         hbox->set_spacing (8);
717         hbox->pack_start (*meter_hold_label, false, false);
718         hbox->pack_start (meter_hold_combo, false, false);
719         display_packer.pack_start (*hbox, false, false);
720
721         Label *meter_falloff_label = manage (new Label (_("Meter Falloff")));
722         meter_falloff_label->set_name ("OptionsLabel");
723         dumb.clear ();
724         dumb.push_back (_("Off"));
725         dumb.push_back (_("Slowest"));
726         dumb.push_back (_("Slow"));
727         dumb.push_back (_("Medium"));
728         dumb.push_back (_("Fast"));
729         dumb.push_back (_("Faster"));
730         dumb.push_back (_("Fastest"));
731         set_popdown_strings (meter_falloff_combo, dumb);
732         meter_falloff_combo.signal_changed().connect (mem_fun(*this, &OptionEditor::meter_falloff_chosen));
733         hbox = manage (new HBox);
734         hbox->set_border_width (8);
735         hbox->set_spacing (8);
736         hbox->pack_start (*meter_falloff_label, false, false);
737         hbox->pack_start (meter_falloff_combo, false, false);
738         display_packer.pack_start (*hbox, false, false);
739         
740         
741         show_waveforms_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::show_waveforms_clicked));
742         show_waveforms_recording_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::show_waveforms_recording_clicked));
743         show_measures_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::show_measures_clicked));
744         mixer_strip_width_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::strip_width_clicked));
745         follow_playhead_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::follow_playhead_clicked));
746
747         editor.DisplayControlChanged.connect (mem_fun(*this, &OptionEditor::display_control_changed));
748
749         show_measures_button.set_active (editor.show_measures());
750         show_waveforms_button.set_active (editor.show_waveforms());
751         show_waveforms_recording_button.set_active (editor.show_waveforms_recording());
752         follow_playhead_button.set_active (editor.follow_playhead());
753 }
754
755 void
756 OptionEditor::meter_hold_chosen ()
757 {
758         if (session) {
759                 string str = meter_hold_combo.get_active_text();
760                 
761                 if (str == _("Off")) {
762                         session->set_meter_hold (0);
763                 } else if (str == _("Short")) {
764                         session->set_meter_hold (40);
765                 } else if (str == _("Medium")) {
766                         session->set_meter_hold (100);
767                 } else if (str == _("Long")) {
768                         session->set_meter_hold (200);
769                 }
770         }
771 }
772
773 void
774 OptionEditor::meter_falloff_chosen ()
775 {
776         if (session) {
777                 string str = meter_falloff_combo.get_active_text();
778                 
779                 if (str == _("Off")) {
780                         session->set_meter_falloff (0.0f);
781                 } else if (str == _("Slowest")) {
782                         session->set_meter_falloff (0.266f); // 6.6 dB/sec falloff at update rate of 40 ms
783                 } else if (str == _("Slow")) {
784                         session->set_meter_falloff (0.342f); // 8.6 dB/sec falloff at update rate of 40 ms
785                 } else if (str == _("Medium")) {
786                         session->set_meter_falloff  (0.7f);
787                 } else if (str == _("Fast")) {
788                         session->set_meter_falloff (1.1f);
789                 } else if (str == _("Faster")) {
790                         session->set_meter_falloff (1.5f);
791                 } else if (str == _("Fastest")) {
792                         session->set_meter_falloff (2.5f);
793                 }
794         }
795 }
796
797 void
798 OptionEditor::display_control_changed (Editing::DisplayControl dc)
799 {
800         ToggleButton* button = 0;
801         bool val = true;
802
803         switch (dc) {
804         case ShowMeasures:
805                 val = editor.show_measures ();
806                 button = &show_measures_button;
807                 break;
808         case ShowWaveforms:
809                 val = editor.show_waveforms ();
810                 button = &show_waveforms_button;
811                 break;
812         case ShowWaveformsRecording:
813                 val = editor.show_waveforms_recording ();
814                 button = &show_waveforms_recording_button;
815                 break;
816         case FollowPlayhead:
817                 val = editor.follow_playhead ();
818                 button = &follow_playhead_button;
819                 break;
820         }
821
822         if (button->get_active() != val) {
823                 button->set_active (val);
824         }
825 }
826
827 void
828 OptionEditor::setup_sync_options ()
829 {
830         Label *slave_type_label = manage (new Label (_("Positional Sync")));
831         HBox* hbox;
832         vector<string> dumb;
833
834         slave_type_label->set_name("OptionsLabel");
835         positional_sync_strings = internationalize (psync_strings);
836
837         slave_type_combo.set_name ("OptionsEntry");
838         slave_type_combo.signal_changed().connect (mem_fun(*this, &OptionEditor::slave_type_chosen));
839
840         dumb.clear ();
841         dumb.push_back (X_("24 FPS"));
842         dumb.push_back (X_("25 FPS"));
843         dumb.push_back (X_("30 FPS drop"));
844         dumb.push_back (X_("30 FPS non-drop"));
845         
846         set_popdown_strings (smpte_fps_combo, dumb);
847         smpte_fps_combo.signal_changed().connect (mem_fun(*this, &OptionEditor::smpte_fps_chosen));
848         
849         smpte_offset_clock.set_mode (AudioClock::SMPTE);
850         smpte_offset_clock.ValueChanged.connect (mem_fun(*this, &OptionEditor::smpte_offset_chosen));
851         
852         send_mtc_button.set_name ("OptionEditorToggleButton");
853         jack_time_master_button.set_name ("OptionEditorToggleButton");
854         smpte_offset_negative_button.set_name ("OptionEditorToggleButton");
855
856         send_mtc_button.unset_flags (Gtk::CAN_FOCUS);
857         jack_time_master_button.unset_flags (Gtk::CAN_FOCUS);
858         smpte_offset_negative_button.unset_flags (Gtk::CAN_FOCUS);
859
860         hbox = manage (new HBox);
861         hbox->set_border_width (5);
862         hbox->set_spacing (10);
863         hbox->pack_start (*slave_type_label, false, false);
864         hbox->pack_start (slave_type_combo, false, false);
865
866         sync_packer.pack_start (*hbox, false, false);
867         
868         hbox = manage (new HBox);
869         hbox->set_border_width (5);
870         hbox->pack_start (send_mtc_button, false, false);
871         sync_packer.pack_start (*hbox, false, false);
872
873         hbox = manage (new HBox);
874         hbox->set_border_width (5);
875         hbox->pack_start (jack_time_master_button, false, false);
876         sync_packer.pack_start (*hbox, false, false);
877
878         Label *smpte_fps_label = manage (new Label (_("SMPTE Frames/second")));
879         Label *smpte_offset_label = manage (new Label (_("SMPTE Offset")));
880         smpte_fps_label->set_name("OptionsLabel");
881         smpte_offset_label->set_name("OptionsLabel");
882         
883         hbox = manage (new HBox);
884         hbox->set_border_width (5);
885         hbox->set_spacing (10);
886         hbox->pack_start (*smpte_fps_label, false, false);
887         hbox->pack_start (smpte_fps_combo, false, false);
888
889         sync_packer.pack_start (*hbox, false, false);
890
891         hbox = manage (new HBox);
892         hbox->set_border_width (5);
893         hbox->set_spacing (10);
894         hbox->pack_start (*smpte_offset_label, false, false);
895         hbox->pack_start (smpte_offset_clock, false, false);
896         hbox->pack_start (smpte_offset_negative_button, false, false);
897
898         sync_packer.pack_start (*hbox, false, false);
899
900         jack_time_master_button.set_active (Config->get_jack_time_master());
901
902         send_mtc_button.signal_button_press_event().connect (bind (mem_fun(*this, &OptionEditor::send_mtc_toggled), &send_mtc_button));
903         jack_time_master_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::jack_time_master_clicked));
904         smpte_offset_negative_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::smpte_offset_negative_clicked));
905 }
906
907 void
908 OptionEditor::smpte_offset_negative_clicked ()
909 {
910         if (session) {
911                 session->set_smpte_offset_negative (smpte_offset_negative_button.get_active());
912         }
913 }
914
915 void
916 OptionEditor::smpte_fps_chosen ()
917 {
918         if (session) {
919                 string str = smpte_fps_combo.get_active_text();
920                 
921                 if (str == X_("24 FPS")) {
922                         session->set_smpte_type (24.0, false);
923                 } else if (str == X_("25 FPS")) {
924                         session->set_smpte_type (25.0, false);
925                 } else if (str == X_("30 FPS drop")) {
926                         session->set_smpte_type (29.97, true);
927                 } else if (str == X_("30 FPS non-drop")) {
928                         session->set_smpte_type (30.0, false);
929                 }
930         }
931 }
932
933 void
934 OptionEditor::smpte_offset_chosen()
935 {
936         if (session) {
937                 jack_nframes_t frames = smpte_offset_clock.current_duration();
938                 session->set_smpte_offset (frames);
939         }
940 }
941
942
943 void
944 OptionEditor::setup_midi_options ()
945 {
946         HBox* hbox;
947         MIDI::Manager::PortMap::const_iterator i;
948         const MIDI::Manager::PortMap& ports = MIDI::Manager::instance()->get_midi_ports();
949         int n;
950         ToggleButton* tb;
951         RadioButton* rb;
952
953         Gtk::Table* table = manage (new Table (ports.size() + 4, 9));
954
955         table->set_row_spacings (6);
956         table->set_col_spacings (10);
957
958         table->attach (*(manage (new Label (X_("Port")))), 0, 1, 0, 1);
959         table->attach (*(manage (new Label (X_("Offline")))), 1, 2, 0, 1);
960         table->attach (*(manage (new Label (X_("Trace\nInput")))), 2, 3, 0, 1);
961         table->attach (*(manage (new Label (X_("Trace\nOutput")))), 3, 4, 0, 1);
962         table->attach (*(manage (new Label (X_("MTC")))), 4, 5, 0, 1);
963         table->attach (*(manage (new Label (X_("MMC")))), 6, 7, 0, 1);
964         table->attach (*(manage (new Label (X_("MIDI Parameter\nControl")))), 8, 9, 0, 1);
965
966         table->attach (*(manage (new HSeparator())), 0, 9, 1, 2);
967         table->attach (*(manage (new VSeparator())), 5, 6, 0, 8);
968         table->attach (*(manage (new VSeparator())), 7, 8, 0, 8);
969         
970         for (n = 0, i = ports.begin(); i != ports.end(); ++n, ++i) {
971
972                 pair<MIDI::Port*,vector<RadioButton*> > newpair;
973
974                 newpair.first = i->second;
975
976                 table->attach (*(manage (new Label (i->first))), 0, 1, n+2, n+3,FILL|EXPAND, FILL );
977                 tb = manage (new ToggleButton (_("online")));
978                 tb->set_name ("OptionEditorToggleButton");
979
980                 /* remember, we have to handle the i18n case where the relative
981                    lengths of the strings in language N is different than in english.
982                 */
983
984                 if (strlen (_("offline")) > strlen (_("online"))) {
985                         set_size_request_to_display_given_text (*tb, _("offline"), 15, 12);
986                 } else {
987                         set_size_request_to_display_given_text (*tb, _("online"), 15, 12);
988                 }
989
990                 tb->set_active (!(*i).second->input()->offline());
991                 tb->signal_button_press_event().connect (bind (mem_fun(*this, &OptionEditor::port_online_toggled), (*i).second, tb));
992                 (*i).second->input()->OfflineStatusChanged.connect (bind (mem_fun(*this, &OptionEditor::map_port_online), (*i).second, tb));
993                 table->attach (*tb, 1, 2, n+2, n+3, FILL|EXPAND, FILL);
994
995                 tb = manage (new ToggleButton ());
996                 tb->set_name ("OptionEditorToggleButton");
997                 tb->signal_button_press_event().connect (bind (mem_fun(*this, &OptionEditor::port_trace_in_toggled), (*i).second, tb));
998                 tb->set_size_request (10, 10);
999                 table->attach (*tb, 2, 3, n+2, n+3, FILL|EXPAND, FILL);
1000
1001                 tb = manage (new ToggleButton ());
1002                 tb->set_name ("OptionEditorToggleButton");
1003                 tb->signal_button_press_event().connect (bind (mem_fun(*this, &OptionEditor::port_trace_out_toggled), (*i).second, tb));
1004                 tb->set_size_request (10, 10);
1005                 table->attach (*tb, 3, 4, n+2, n+3, FILL|EXPAND, FILL);
1006
1007                 rb = manage (new RadioButton ());
1008                 newpair.second.push_back (rb);
1009                 rb->set_name ("OptionEditorToggleButton");
1010                 if (n == 0) {
1011                         mtc_button_group = rb->get_group();
1012                 } else {
1013                         rb->set_group (mtc_button_group);
1014
1015                 }
1016                 table->attach (*rb, 4, 5, n+2, n+3, FILL|EXPAND, FILL);
1017                 rb->signal_button_press_event().connect (bind (mem_fun(*this, &OptionEditor::mtc_port_chosen), (*i).second, rb));
1018
1019                 if (Config->get_mtc_port_name() == i->first) {
1020                         rb->set_active (true);
1021                 }
1022                 
1023                 rb = manage (new RadioButton ());
1024                 newpair.second.push_back (rb);
1025                 rb->set_name ("OptionEditorToggleButton");
1026                 if (n == 0) {
1027                         mmc_button_group = rb->get_group();
1028                 } else {
1029                         rb->set_group (mmc_button_group);
1030                 }
1031                 table->attach (*rb, 6, 7, n+2, n+3, FILL|EXPAND, FILL);
1032                 rb->signal_button_press_event().connect (bind (mem_fun(*this, &OptionEditor::mmc_port_chosen), (*i).second, rb));
1033
1034                 if (Config->get_mmc_port_name() == i->first) {
1035                         rb->set_active (true);
1036                 }
1037
1038                 rb = manage (new RadioButton ());
1039                 newpair.second.push_back (rb);
1040                 rb->set_name ("OptionEditorToggleButton");
1041                 if (n == 0) {
1042                         midi_button_group = rb->get_group();
1043                 } else {
1044                         rb->set_group (midi_button_group);
1045                 }
1046                 table->attach (*rb, 8, 9, n+2, n+3, FILL|EXPAND, FILL);
1047                 rb->signal_button_press_event().connect (bind (mem_fun(*this, &OptionEditor::midi_port_chosen), (*i).second, rb));
1048
1049                 if (Config->get_midi_port_name() == i->first) {
1050                         rb->set_active (true);
1051                 }
1052                 
1053                 port_toggle_buttons.insert (newpair);
1054         }
1055
1056         table->show_all ();
1057
1058         hbox = manage (new HBox);
1059         hbox->set_border_width (6);
1060         hbox->pack_start (*table, true, false);
1061         midi_packer.pack_start (*hbox, false, false);
1062         
1063         VBox* mmcbuttonbox = manage (new VBox);
1064
1065         mmc_control_button.set_name ("OptionEditorToggleButton");
1066
1067         hbox = manage (new HBox);
1068         hbox->set_border_width (6);
1069         hbox->pack_start (mmc_control_button, false, false, 36);
1070         mmcbuttonbox->pack_start (*hbox, false, false);
1071
1072         midi_control_button.set_name ("OptionEditorToggleButton");
1073
1074         hbox = manage (new HBox);
1075         hbox->set_border_width (6);
1076         hbox->pack_start (midi_control_button, false, false, 36);
1077         mmcbuttonbox->pack_start (*hbox, false, false);
1078
1079         send_mmc_button.set_name ("OptionEditorToggleButton");
1080
1081         hbox = manage (new HBox);
1082         hbox->set_border_width (6);
1083         hbox->pack_start (send_mmc_button, false, false, 36);
1084         mmcbuttonbox->pack_start (*hbox, false, false);
1085         
1086         midi_feedback_button.set_name ("OptionEditorToggleButton");
1087
1088         hbox = manage (new HBox);
1089         hbox->set_border_width (6);
1090         hbox->pack_start (midi_feedback_button, false, false, 36);
1091         mmcbuttonbox->pack_start (*hbox, false, false);
1092
1093         midi_packer.pack_start (*mmcbuttonbox, false, false);
1094
1095         mmc_control_button.signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::mmc_control_toggled), &mmc_control_button));
1096         midi_control_button.signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::midi_control_toggled), &midi_control_button));
1097         send_mmc_button.signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::send_mmc_toggled), &send_mmc_button));
1098         midi_feedback_button.signal_toggled().connect (bind (mem_fun(*this, &OptionEditor::midi_feedback_toggled), &midi_feedback_button));
1099 }
1100
1101 gint
1102 OptionEditor::mtc_port_chosen (GdkEventButton* ev, MIDI::Port *port, Gtk::RadioButton* rb) 
1103 {
1104         if (session) {
1105                 if (!rb->get_active()) {
1106                         if (port) {
1107                                 session->set_mtc_port (port->name());
1108                                 Config->set_mtc_port_name (port->name());
1109                         } else {
1110                                 session->set_mtc_port ("");
1111                         }
1112
1113                         /* update sync options to reflect MTC port availability */
1114
1115                         vector<string> dumb;
1116                         dumb.push_back (positional_sync_strings[Session::None]);
1117                         dumb.push_back (positional_sync_strings[Session::JACK]);
1118
1119                         if (session->mtc_port()) {
1120                                 dumb.push_back (positional_sync_strings[Session::MTC]);
1121                         }
1122                         set_popdown_strings (slave_type_combo, dumb);
1123
1124                         rb->set_active (true);
1125                 }
1126         }
1127
1128         return stop_signal (*rb, "button_press_event");
1129 }
1130
1131 gint
1132 OptionEditor::mmc_port_chosen (GdkEventButton* ev, MIDI::Port* port, Gtk::RadioButton* rb)
1133 {
1134         if (session) {
1135                 if (!rb->get_active()) {
1136                         if (port) {
1137                                 session->set_mmc_port (port->name());
1138                                 Config->set_mtc_port_name (port->name());
1139                         } else {
1140                                 session->set_mmc_port ("");
1141                         }
1142                         rb->set_active (true);
1143                 }
1144         }
1145         return stop_signal (*rb, "button_press_event");
1146 }
1147
1148 gint
1149 OptionEditor::midi_port_chosen (GdkEventButton* ev, MIDI::Port* port, Gtk::RadioButton* rb)
1150 {
1151         if (session) {
1152                 if (!rb->get_active()) {
1153                         if (port) {
1154                                 session->set_midi_port (port->name());
1155                                 Config->set_midi_port_name (port->name());
1156                         } else {
1157                                 session->set_midi_port ("");
1158                         }
1159                         rb->set_active (true);
1160                 }
1161         }
1162         return stop_signal (*rb, "button_press_event");
1163 }
1164
1165 gint
1166 OptionEditor::port_online_toggled (GdkEventButton* ev, MIDI::Port* port, ToggleButton* tb)
1167 {
1168         bool wanted = tb->get_active(); /* it hasn't changed at this point */
1169
1170         if (wanted != port->input()->offline()) {
1171                 port->input()->set_offline (wanted);
1172         } 
1173         return stop_signal (*tb, "button_press_event");
1174 }
1175
1176 void
1177 OptionEditor::map_port_online (MIDI::Port* port, ToggleButton* tb)
1178 {
1179         if (port->input()->offline()) {
1180                 static_cast<Label*>(tb->get_child())->set_text (_("offline"));
1181                 tb->set_active (false);
1182         } else {
1183                 static_cast<Label*>(tb->get_child())->set_text (_("online"));
1184                 tb->set_active (true);
1185         }
1186 }
1187
1188 gint
1189 OptionEditor::port_trace_in_toggled (GdkEventButton* ev, MIDI::Port* port, ToggleButton* tb)
1190 {
1191         /* XXX not very good MVC style here */
1192
1193         port->input()->trace (!tb->get_active(), &cerr, string (port->name()) + string (" input: "));
1194         tb->set_active (!tb->get_active());
1195         return stop_signal (*tb, "button_press_event");
1196 }
1197
1198 gint
1199 OptionEditor::port_trace_out_toggled (GdkEventButton* ev,MIDI::Port* port, ToggleButton* tb)
1200 {
1201         /* XXX not very good MVC style here */
1202
1203         port->output()->trace (!tb->get_active(), &cerr, string (port->name()) + string (" output: "));
1204         tb->set_active (!tb->get_active());
1205         return stop_signal (*tb, "button_press_event");
1206 }
1207
1208 gint
1209 OptionEditor::send_mtc_toggled (GdkEventButton *ev, CheckButton *button)
1210 {
1211         if (session) {
1212                 session->set_send_mtc (!button->get_active());
1213         }
1214         return stop_signal (*button, "button_press_event");
1215 }
1216
1217 void
1218 OptionEditor::send_mmc_toggled (CheckButton *button)
1219 {
1220         if (session) {
1221                 session->set_send_mmc (button->get_active());
1222         }
1223 }
1224
1225 void
1226 OptionEditor::mmc_control_toggled (CheckButton *button)
1227 {
1228         if (session) {
1229                 session->set_mmc_control (button->get_active());
1230         }
1231 }
1232
1233 void
1234 OptionEditor::midi_control_toggled (CheckButton *button)
1235 {
1236         if (session) {
1237                 session->set_midi_control (button->get_active());
1238         }
1239 }
1240
1241 void
1242 OptionEditor::midi_feedback_toggled (CheckButton *button)
1243 {
1244         if (session) {
1245                 session->set_midi_feedback (button->get_active());
1246         }
1247 }
1248
1249 void
1250 OptionEditor::save ()
1251 {
1252         /* XXX a bit odd that we save the entire session state here */
1253
1254         ui.save_state ("");
1255 }
1256
1257 gint
1258 OptionEditor::wm_close (GdkEventAny *ev)
1259 {
1260         save ();
1261         just_close_win();
1262         return TRUE;
1263 }
1264
1265 void
1266 OptionEditor::jack_time_master_clicked ()
1267 {
1268         bool yn = jack_time_master_button.get_active();
1269
1270         Config->set_jack_time_master (yn);
1271
1272         if (session) {
1273                 session->engine().reset_timebase ();
1274         }
1275 }
1276
1277 void
1278 OptionEditor::raid_path_changed ()
1279 {
1280         if (session) {
1281                 session->set_raid_path (session_raid_entry.get_text());
1282         }
1283 }
1284
1285 void
1286 OptionEditor::click_browse_clicked ()
1287 {
1288         SoundFileChooser sfdb (_("Choose Click"));
1289         
1290         int result = sfdb.run ();
1291
1292         if (result == Gtk::RESPONSE_OK) {
1293                 click_chosen(sfdb.get_filename());
1294         }
1295 }
1296
1297 void
1298 OptionEditor::click_chosen (string path)
1299 {
1300         click_path_entry.set_text (path);
1301         click_sound_changed ();
1302 }
1303
1304 void
1305 OptionEditor::click_emphasis_browse_clicked ()
1306 {
1307         SoundFileChooser sfdb (_("Choose Click Emphasis"));
1308
1309         int result = sfdb.run ();
1310
1311         if (result == Gtk::RESPONSE_OK) {
1312                 click_emphasis_chosen (sfdb.get_filename());
1313         }
1314 }
1315
1316 void
1317 OptionEditor::click_emphasis_chosen (std::string path)
1318 {       
1319         click_emphasis_path_entry.set_text (path);
1320         click_emphasis_sound_changed ();
1321 }
1322
1323 void
1324 OptionEditor::click_sound_changed ()
1325 {
1326         if (session) {
1327                 string path = click_path_entry.get_text();
1328
1329                 if (path == session->click_sound) {
1330                         return;
1331                 }
1332
1333                 if (path.length() == 0) {
1334
1335                         session->set_click_sound ("");
1336
1337                 } else {
1338
1339                         strip_whitespace_edges (path);
1340                         
1341                         if (path == _("internal")) {
1342                                 session->set_click_sound ("");
1343                         } else {
1344                                 session->set_click_sound (path);
1345                         }
1346                 }
1347         }
1348 }
1349
1350 void
1351 OptionEditor::click_emphasis_sound_changed ()
1352 {
1353         if (session) {
1354                 string path = click_emphasis_path_entry.get_text();
1355
1356                 if (path == session->click_emphasis_sound) {
1357                         return;
1358                 }
1359
1360                 if (path.length() == 0) {
1361
1362                         session->set_click_emphasis_sound ("");
1363
1364                 } else {
1365
1366                         strip_whitespace_edges (path);
1367
1368                         if (path == _("internal")) {
1369                                 session->set_click_emphasis_sound ("");
1370                         } else {
1371                                 session->set_click_emphasis_sound (path);
1372                         }
1373                 }
1374         }
1375 }
1376
1377 void
1378 OptionEditor::show_waveforms_clicked ()
1379 {
1380         editor.set_show_waveforms (show_waveforms_button.get_active());
1381 }
1382
1383 void
1384 OptionEditor::show_waveforms_recording_clicked ()
1385 {
1386         editor.set_show_waveforms_recording (show_waveforms_recording_button.get_active());
1387 }
1388
1389 void
1390 OptionEditor::show_measures_clicked ()
1391 {
1392         editor.set_show_measures (show_measures_button.get_active());
1393 }
1394
1395 void
1396 OptionEditor::follow_playhead_clicked ()
1397 {
1398         editor.set_follow_playhead (follow_playhead_button.get_active());
1399 }
1400
1401 void
1402 OptionEditor::strip_width_clicked ()
1403 {
1404         mixer.set_strip_width (mixer_strip_width_button.get_active() ? Narrow : Wide);
1405 }
1406
1407
1408 void
1409 OptionEditor::just_close_win()
1410 {
1411         hide();
1412 }
1413
1414 void
1415 OptionEditor::queue_session_control_changed (Session::ControlType t)
1416 {
1417         ui.call_slot (bind (mem_fun(*this, &OptionEditor::session_control_changed), t));
1418 }
1419
1420 void
1421 OptionEditor::session_control_changed (Session::ControlType t)
1422 {
1423         switch (t) {
1424         case Session::SlaveType:
1425                 switch (session->slave_source()) {
1426                 case Session::None:
1427                         slave_type_combo.set_active_text (positional_sync_strings[Session::None]);
1428                         break;
1429                 case Session::MTC:
1430                         slave_type_combo.set_active_text (positional_sync_strings[Session::MTC]);
1431                         break;
1432                 case Session::JACK:
1433                         slave_type_combo.set_active_text (positional_sync_strings[Session::JACK]);
1434                         break;
1435                 default:
1436                         slave_type_combo.set_active_text (_("--unknown--"));
1437                         break;
1438                 }
1439                 
1440                 break;
1441
1442         case Session::SendMTC:
1443                 map_some_session_state (send_mtc_button, &Session::get_send_mtc);
1444                 break;
1445
1446         case Session::SendMMC:
1447                 map_some_session_state (send_mmc_button, &Session::get_send_mmc);
1448                 break;
1449
1450         case Session::MMCControl:       
1451                 map_some_session_state (mmc_control_button, &Session::get_mmc_control);
1452                 break;
1453
1454         case Session::MidiFeedback:       
1455                 map_some_session_state (midi_feedback_button, &Session::get_midi_feedback);
1456                 break;
1457
1458         case Session::MidiControl:       
1459                  map_some_session_state (midi_control_button, &Session::get_midi_control);
1460                 break;
1461         
1462         default:
1463                 break;
1464         }
1465 }
1466
1467 void
1468 OptionEditor::native_format_chosen ()
1469 {
1470         string which;
1471
1472         if (session == 0) {
1473                 return;
1474         }
1475
1476         bool use_bwf = (native_format_combo.get_active_text() == native_format_strings[0]);
1477
1478         if (use_bwf != Config->get_native_format_is_bwf()) {
1479                 Config->set_native_format_is_bwf (use_bwf);
1480                 session->reset_native_file_format ();
1481         }
1482 }
1483
1484 void
1485 OptionEditor::slave_type_chosen ()
1486 {
1487         string which;
1488
1489         if (session == 0) {
1490                 return;
1491         }
1492
1493         which = slave_type_combo.get_active_text();
1494
1495         if (which == positional_sync_strings[Session::None]) {
1496                 session->request_slave_source (Session::None);
1497         } else if (which == positional_sync_strings[Session::MTC]) {
1498                 session->request_slave_source (Session::MTC);
1499         } else if (which == positional_sync_strings[Session::JACK]) {
1500                 session->request_slave_source (Session::JACK);
1501         } 
1502 }
1503
1504 void
1505 OptionEditor::clear_click_editor ()
1506 {
1507         if (click_io_selector) {
1508                 click_packer.remove (*click_io_selector);
1509                 click_packer.remove (*click_gpm);
1510                 delete click_io_selector;
1511                 delete click_gpm;
1512                 click_io_selector = 0;
1513                 click_gpm = 0;
1514         }
1515 }
1516
1517 void
1518 OptionEditor::setup_click_editor ()
1519 {
1520         Label* label;
1521         HBox* hpacker = manage (new HBox);
1522
1523         click_path_entry.set_sensitive (true);
1524         click_emphasis_path_entry.set_sensitive (true);
1525
1526         click_path_entry.set_name ("OptionsEntry");
1527         click_emphasis_path_entry.set_name ("OptionsEntry");
1528         
1529         click_path_entry.signal_activate().connect (mem_fun(*this, &OptionEditor::click_sound_changed));
1530         click_emphasis_path_entry.signal_activate().connect (mem_fun(*this, &OptionEditor::click_emphasis_sound_changed));
1531
1532         click_path_entry.signal_focus_out_event().connect (bind (mem_fun(*this, &OptionEditor::focus_out_event_handler), &OptionEditor::click_sound_changed));
1533         click_emphasis_path_entry.signal_focus_out_event().connect (bind (mem_fun(*this, &OptionEditor::focus_out_event_handler), &OptionEditor::click_emphasis_sound_changed));
1534
1535         click_browse_button.set_name ("EditorGTKButton");
1536         click_emphasis_browse_button.set_name ("EditorGTKButton");
1537         click_browse_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::click_browse_clicked));
1538         click_emphasis_browse_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::click_emphasis_browse_clicked));
1539
1540         click_packer.set_border_width (12);
1541         click_packer.set_spacing (5);
1542
1543         click_io_selector = new IOSelector (*session, session->click_io(), false);
1544         click_gpm = new GainMeter (session->click_io(), *session);
1545
1546         click_table.set_col_spacings (10);
1547         
1548         label = manage(new Label(_("Click audio file")));
1549         label->set_name ("OptionsLabel");
1550         click_table.attach (*label, 0, 1, 0, 1, FILL|EXPAND, FILL);
1551         click_table.attach (click_path_entry, 1, 2, 0, 1, Gtk::FILL|Gtk::EXPAND, FILL);
1552         click_table.attach (click_browse_button, 2, 3, 0, 1, FILL|EXPAND, FILL);
1553         
1554         label = manage(new Label(_("Click emphasis audiofile")));
1555         label->set_name ("OptionsLabel");
1556         click_table.attach (*label, 0, 1, 1, 2, FILL|EXPAND, FILL);
1557         click_table.attach (click_emphasis_path_entry, 1, 2, 1, 2, Gtk::FILL|Gtk::EXPAND, FILL);
1558         click_table.attach (click_emphasis_browse_button, 2, 3, 1, 2, FILL|EXPAND, FILL);
1559
1560         hpacker->set_spacing (10);
1561         hpacker->pack_start (*click_io_selector, false, false);
1562         hpacker->pack_start (*click_gpm, false, false);
1563
1564         click_packer.pack_start (click_table, false, false);
1565         click_packer.pack_start (*hpacker, false, false);
1566
1567         click_packer.show_all ();
1568 }
1569
1570 void
1571 OptionEditor::clear_auditioner_editor ()
1572 {
1573         if (auditioner_io_selector) {
1574                 audition_hpacker.remove (*auditioner_io_selector);
1575                 audition_hpacker.remove (*auditioner_gpm);
1576                 delete auditioner_io_selector;
1577                 delete auditioner_gpm;
1578                 auditioner_io_selector = 0;
1579                 auditioner_gpm = 0;
1580         }
1581 }
1582
1583 void
1584 OptionEditor::setup_auditioner_editor ()
1585 {
1586         audition_packer.set_border_width (12);
1587         audition_packer.set_spacing (5);
1588         audition_hpacker.set_spacing (10);
1589
1590         audition_label.set_name ("OptionEditorAuditionerLabel");
1591         audition_label.set_text (_("The auditioner is a dedicated mixer strip used\n"
1592                                    "for listening to specific regions outside the context\n"
1593                                    "of the overall mix. It can be connected just like any\n"
1594                                    "other mixer strip."));
1595         
1596         audition_packer.pack_start (audition_label, false, false, 10);
1597         audition_packer.pack_start (audition_hpacker, false, false);
1598 }
1599
1600 void
1601 OptionEditor::connect_audition_editor ()
1602 {
1603         auditioner_io_selector = new IOSelector (*session, session->the_auditioner(), false);
1604         auditioner_gpm = new GainMeter (session->the_auditioner(), *session);
1605
1606         audition_hpacker.pack_start (*auditioner_io_selector, false, false);
1607         audition_hpacker.pack_start (*auditioner_gpm, false, false);
1608
1609         auditioner_io_selector->show_all ();
1610         auditioner_gpm->show_all ();
1611 }
1612
1613 bool
1614 OptionEditor::focus_out_event_handler (GdkEventFocus* ev, void (OptionEditor::*pmf)()) 
1615 {
1616         (this->*pmf)();
1617         return false;
1618 }
1619
1620 void
1621 OptionEditor::setup_misc_options()
1622 {
1623         Gtk::Table* table = manage (new Table (4, 2));  
1624         table->set_homogeneous (true);
1625
1626         misc_packer.set_border_width (8);
1627         misc_packer.set_spacing (3);
1628         misc_packer.pack_start (*table, true, true);
1629
1630         table->attach (hw_monitor_button, 0, 1, 0, 1, Gtk::FILL, FILL, 8, 0);
1631         table->attach (sw_monitor_button, 0, 1, 1, 2, Gtk::FILL, FILL, 8, 0);
1632         table->attach (plugins_stop_button, 0, 1, 2, 3, Gtk::FILL, FILL, 8, 0);
1633         table->attach (plugins_on_rec_button, 0, 1, 3, 4, Gtk::FILL, FILL, 8, 0);
1634         table->attach (verify_remove_last_capture_button, 0, 1, 4, 5, Gtk::FILL, FILL, 8, 0);
1635
1636         table->attach (stop_rec_on_xrun_button, 1, 2, 0, 1, Gtk::FILL, FILL, 8, 0);
1637         table->attach (stop_at_end_button, 1, 2, 1, 2, Gtk::FILL, FILL, 8, 0);
1638         table->attach (debug_keyboard_button, 1, 2, 2, 3, Gtk::FILL, FILL, 8, 0);
1639         table->attach (speed_quieten_button, 1, 2, 3, 4, Gtk::FILL, FILL, 8, 0);
1640
1641         Gtk::VBox* connect_box = manage (new VBox);
1642         connect_box->set_spacing (3);
1643         connect_box->set_border_width (8);
1644
1645         auto_connect_output_button_group = auto_connect_output_master_button.get_group();
1646         auto_connect_output_manual_button.set_group (auto_connect_output_button_group);
1647         auto_connect_output_physical_button.set_group (auto_connect_output_button_group);
1648
1649         Gtk::HBox* useless_box = manage (new HBox);
1650         useless_box->pack_start (auto_connect_inputs_button, false, false);
1651         connect_box->pack_start (*useless_box, false, false);
1652         connect_box->pack_start (auto_connect_output_master_button, false, false);
1653         connect_box->pack_start (auto_connect_output_physical_button, false, false);
1654         connect_box->pack_start (auto_connect_output_manual_button, false, false);
1655
1656         misc_packer.pack_start (*connect_box, false, false);
1657         
1658         hw_monitor_button.set_name ("OptionEditorToggleButton");
1659         sw_monitor_button.set_name ("OptionEditorToggleButton");
1660         plugins_stop_button.set_name ("OptionEditorToggleButton");
1661         plugins_on_rec_button.set_name ("OptionEditorToggleButton");
1662         verify_remove_last_capture_button.set_name ("OptionEditorToggleButton");
1663         auto_connect_inputs_button.set_name ("OptionEditorToggleButton");
1664         auto_connect_output_physical_button.set_name ("OptionEditorToggleButton");
1665         auto_connect_output_master_button.set_name ("OptionEditorToggleButton");
1666         auto_connect_output_manual_button.set_name ("OptionEditorToggleButton");
1667         stop_rec_on_xrun_button.set_name ("OptionEditorToggleButton");
1668         stop_at_end_button.set_name ("OptionEditorToggleButton");
1669         debug_keyboard_button.set_name ("OptionEditorToggleButton");
1670         speed_quieten_button.set_name ("OptionEditorToggleButton");
1671
1672         hw_monitor_button.set_active (Config->get_use_hardware_monitoring());
1673         sw_monitor_button.set_active (!Config->get_no_sw_monitoring());
1674         plugins_stop_button.set_active (Config->get_plugins_stop_with_transport());
1675         stop_rec_on_xrun_button.set_active (Config->get_stop_recording_on_xrun());
1676         stop_at_end_button.set_active (Config->get_stop_at_session_end());
1677         debug_keyboard_button.set_active (false);
1678         speed_quieten_button.set_active (Config->get_quieten_at_speed() != 1.0f);
1679
1680         hw_monitor_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::hw_monitor_clicked));
1681         sw_monitor_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::sw_monitor_clicked));
1682         plugins_stop_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::plugins_stop_with_transport_clicked));
1683         plugins_on_rec_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::plugins_on_while_recording_clicked));
1684         verify_remove_last_capture_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::verify_remove_last_capture_clicked));
1685         auto_connect_inputs_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::auto_connect_inputs_clicked));
1686         auto_connect_output_physical_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::auto_connect_output_physical_clicked));
1687         auto_connect_output_master_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::auto_connect_output_master_clicked));
1688         auto_connect_output_manual_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::auto_connect_output_manual_clicked));
1689         stop_rec_on_xrun_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::stop_rec_on_xrun_clicked));
1690         stop_at_end_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::stop_at_end_clicked));
1691         debug_keyboard_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::debug_keyboard_clicked));
1692         speed_quieten_button.signal_clicked().connect (mem_fun(*this, &OptionEditor::speed_quieten_clicked));
1693 }
1694
1695 void
1696 OptionEditor::speed_quieten_clicked ()
1697 {
1698         if (speed_quieten_button.get_active()) {
1699                 Config->set_quieten_at_speed (0.251189); // -12dB reduction for ffwd or rewind
1700         } else {
1701                 Config->set_quieten_at_speed (1.0); /* no change */
1702         }
1703 }
1704
1705 void
1706 OptionEditor::debug_keyboard_clicked ()
1707 {
1708         extern bool debug_keyboard;
1709         debug_keyboard = debug_keyboard_button.get_active ();
1710 }
1711
1712 void
1713 OptionEditor::auto_connect_inputs_clicked ()
1714 {
1715         if (session) {
1716                 session->set_input_auto_connect (auto_connect_inputs_button.get_active());
1717         }
1718 }
1719
1720 void
1721 OptionEditor::auto_connect_output_master_clicked ()
1722 {
1723         if (session) {
1724                 if (auto_connect_output_master_button.get_active()) {
1725                         session->set_output_auto_connect (Session::AutoConnectMaster);
1726                 } 
1727         }
1728 }
1729
1730 void
1731 OptionEditor::auto_connect_output_physical_clicked ()
1732 {
1733         if (session) {
1734                 if (auto_connect_output_physical_button.get_active()) {
1735                         session->set_output_auto_connect (Session::AutoConnectPhysical);
1736                 } 
1737         }
1738 }
1739
1740 void
1741 OptionEditor::auto_connect_output_manual_clicked ()
1742 {
1743         if (session) {
1744                 if (auto_connect_output_manual_button.get_active()) {
1745                         session->set_output_auto_connect (Session::AutoConnectOption (0));
1746                 } 
1747         }
1748 }
1749
1750 void
1751 OptionEditor::hw_monitor_clicked ()
1752 {
1753         Config->set_use_hardware_monitoring (hw_monitor_button.get_active());
1754 }
1755
1756 void
1757 OptionEditor::sw_monitor_clicked ()
1758 {
1759         Config->set_no_sw_monitoring (!sw_monitor_button.get_active());
1760 }
1761
1762 void
1763 OptionEditor::plugins_stop_with_transport_clicked ()
1764 {
1765         Config->set_plugins_stop_with_transport (plugins_stop_button.get_active());
1766 }
1767
1768 void
1769 OptionEditor::plugins_on_while_recording_clicked ()
1770 {
1771         if (session) {
1772                 session->set_recording_plugins (plugins_on_rec_button.get_active());
1773         }
1774 }
1775
1776 void
1777 OptionEditor::verify_remove_last_capture_clicked ()
1778 {
1779         Config->set_verify_remove_last_capture(verify_remove_last_capture_button.get_active());
1780 }
1781
1782 void
1783 OptionEditor::stop_rec_on_xrun_clicked ()
1784 {
1785         Config->set_stop_recording_on_xrun (stop_rec_on_xrun_button.get_active());
1786 }
1787
1788 void
1789 OptionEditor::stop_at_end_clicked ()
1790 {
1791         Config->set_stop_at_session_end (stop_at_end_button.get_active());
1792 }
1793                                                   
1794 static const struct {
1795     const char *name;
1796     guint   modifier;
1797 } modifiers[] = {
1798         { "Shift", GDK_SHIFT_MASK },
1799         { "Control", GDK_CONTROL_MASK },
1800         { "Alt (Mod1)", GDK_MOD1_MASK },
1801         { "Control-Shift", GDK_CONTROL_MASK|GDK_SHIFT_MASK },
1802         { "Control-Alt", GDK_CONTROL_MASK|GDK_MOD1_MASK },
1803         { "Shift-Alt", GDK_SHIFT_MASK|GDK_MOD1_MASK },
1804         { "Control-Shift-Alt", GDK_CONTROL_MASK|GDK_SHIFT_MASK|GDK_MOD1_MASK },
1805         { "Mod2", GDK_MOD2_MASK },
1806         { "Mod3", GDK_MOD3_MASK },
1807         { "Mod4", GDK_MOD4_MASK },
1808         { "Mod5", GDK_MOD5_MASK },
1809         { 0, 0 }
1810 };
1811
1812 void
1813 OptionEditor::setup_keyboard_options ()
1814 {
1815         vector<string> dumb;
1816         Label* label;
1817
1818         keyboard_mouse_table.set_border_width (12);
1819         keyboard_mouse_table.set_row_spacings (5);
1820         keyboard_mouse_table.set_col_spacings (5);
1821
1822         /* internationalize and prepare for use with combos */
1823
1824         for (int i = 0; modifiers[i].name; ++i) {
1825                 dumb.push_back (_(modifiers[i].name));
1826         }
1827
1828         set_popdown_strings (edit_modifier_combo, dumb);
1829         edit_modifier_combo.signal_changed().connect (mem_fun(*this, &OptionEditor::edit_modifier_chosen));
1830
1831         for (int x = 0; modifiers[x].name; ++x) {
1832                 if (modifiers[x].modifier == Keyboard::edit_modifier ()) {
1833                         edit_modifier_combo.set_active_text (_(modifiers[x].name));
1834                         break;
1835                 }
1836         }
1837
1838         label = manage (new Label (_("Edit using")));
1839         label->set_name ("OptionsLabel");
1840         label->set_alignment (1.0, 0.5);
1841                 
1842         keyboard_mouse_table.attach (*label, 0, 1, 0, 1, Gtk::FILL|Gtk::EXPAND, FILL);
1843         keyboard_mouse_table.attach (edit_modifier_combo, 1, 2, 0, 1, Gtk::FILL|Gtk::EXPAND, FILL);
1844
1845         label = manage (new Label (_("+ button")));
1846         label->set_name ("OptionsLabel");
1847         
1848         keyboard_mouse_table.attach (*label, 3, 4, 0, 1, Gtk::FILL|Gtk::EXPAND, FILL);
1849         keyboard_mouse_table.attach (edit_button_spin, 4, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, FILL);
1850
1851         edit_button_spin.set_name ("OptionsEntry");
1852         edit_button_adjustment.set_value (Keyboard::edit_button());
1853         edit_button_adjustment.signal_value_changed().connect (mem_fun(*this, &OptionEditor::edit_button_changed));
1854
1855         set_popdown_strings (delete_modifier_combo, dumb);
1856         delete_modifier_combo.signal_changed().connect (mem_fun(*this, &OptionEditor::delete_modifier_chosen));
1857
1858         for (int x = 0; modifiers[x].name; ++x) {
1859                 if (modifiers[x].modifier == Keyboard::delete_modifier ()) {
1860                         delete_modifier_combo.set_active_text (_(modifiers[x].name));
1861                         break;
1862                 }
1863         }
1864
1865         label = manage (new Label (_("Delete using")));
1866         label->set_name ("OptionsLabel");
1867         label->set_alignment (1.0, 0.5);
1868                 
1869         keyboard_mouse_table.attach (*label, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, FILL);
1870         keyboard_mouse_table.attach (delete_modifier_combo, 1, 2, 1, 2, Gtk::FILL|Gtk::EXPAND, FILL);
1871
1872         label = manage (new Label (_("+ button")));
1873         label->set_name ("OptionsLabel");
1874
1875         keyboard_mouse_table.attach (*label, 3, 4, 1, 2, Gtk::FILL|Gtk::EXPAND, FILL);
1876         keyboard_mouse_table.attach (delete_button_spin, 4, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, FILL);
1877
1878         delete_button_spin.set_name ("OptionsEntry");
1879         delete_button_adjustment.set_value (Keyboard::delete_button());
1880         delete_button_adjustment.signal_value_changed().connect (mem_fun(*this, &OptionEditor::delete_button_changed));
1881
1882         set_popdown_strings (snap_modifier_combo, dumb);
1883         snap_modifier_combo.signal_changed().connect (mem_fun(*this, &OptionEditor::snap_modifier_chosen));
1884         
1885         for (int x = 0; modifiers[x].name; ++x) {
1886                 if (modifiers[x].modifier == (guint) Keyboard::snap_modifier ()) {
1887                         snap_modifier_combo.set_active_text (_(modifiers[x].name));
1888                         break;
1889                 }
1890         }
1891
1892         label = manage (new Label (_("Ignore snap using")));
1893         label->set_name ("OptionsLabel");
1894         label->set_alignment (1.0, 0.5);
1895         
1896         keyboard_mouse_table.attach (*label, 0, 1, 2, 3, Gtk::FILL|Gtk::EXPAND, FILL);
1897         keyboard_mouse_table.attach (snap_modifier_combo, 1, 2, 2, 3, Gtk::FILL|Gtk::EXPAND, FILL);
1898 }
1899
1900 void
1901 OptionEditor::edit_modifier_chosen ()
1902 {
1903         string txt;
1904         
1905         txt = edit_modifier_combo.get_active_text();
1906
1907         for (int i = 0; modifiers[i].name; ++i) {
1908                 if (txt == _(modifiers[i].name)) {
1909                         Keyboard::set_edit_modifier (modifiers[i].modifier);
1910                         break;
1911                 }
1912         }
1913 }
1914
1915 void
1916 OptionEditor::delete_modifier_chosen ()
1917 {
1918         string txt;
1919         
1920         txt = delete_modifier_combo.get_active_text();
1921
1922         for (int i = 0; modifiers[i].name; ++i) {
1923                 if (txt == _(modifiers[i].name)) {
1924                         Keyboard::set_delete_modifier (modifiers[i].modifier);
1925                         break;
1926                 }
1927         }
1928 }
1929
1930 void
1931 OptionEditor::snap_modifier_chosen ()
1932 {
1933         string txt;
1934         
1935         txt = snap_modifier_combo.get_active_text();
1936
1937         for (int i = 0; modifiers[i].name; ++i) {
1938                 if (txt == _(modifiers[i].name)) {
1939                         Keyboard::set_snap_modifier (modifiers[i].modifier);
1940                         break;
1941                 }
1942         }
1943 }
1944
1945 void
1946 OptionEditor::delete_button_changed ()
1947 {
1948         Keyboard::set_delete_button ((guint) delete_button_adjustment.get_value());
1949 }
1950
1951 void
1952 OptionEditor::edit_button_changed ()
1953 {
1954         Keyboard::set_edit_button ((guint) edit_button_adjustment.get_value());
1955 }
1956
1957 void
1958 OptionEditor::fixup_combo_size (Gtk::ComboBoxText& combo, vector<string>& strings)
1959 {
1960         /* find the widest string */
1961
1962         string::size_type maxlen = 0;
1963         string maxstring;
1964
1965         for (vector<string>::iterator i = strings.begin(); i != strings.end(); ++i) {
1966                 string::size_type l;
1967
1968                 if ((l = (*i).length()) > maxlen) {
1969                         maxlen = l;
1970                         maxstring = *i;
1971                 }
1972         }
1973
1974         /* try to include ascenders and descenders */
1975
1976         if (maxstring.length() > 2) {
1977                 maxstring[0] = 'g';
1978                 maxstring[1] = 'l';
1979         }
1980
1981         const guint32 FUDGE = 10; // Combo's are stupid - they steal space from the entry for the button
1982
1983         set_size_request_to_display_given_text (combo, maxstring.c_str(), 10 + FUDGE, 10);
1984 }
1985
1986 void
1987 OptionEditor::map_some_session_state (CheckButton& button, bool (Session::*get)() const)
1988 {
1989         if (session) {
1990                 button.set_active ((session->*get)());
1991         }
1992 }
1993