Allow right-click on region list to select the region. Fixes #3129.
[ardour.git] / gtk2_ardour / monitor_section.cc
1 #include <gdkmm/pixbuf.h>
2
3 #include "pbd/compose.h"
4 #include "pbd/error.h"
5
6 #include "gtkmm2ext/bindable_button.h"
7 #include "gtkmm2ext/tearoff.h"
8 #include "gtkmm2ext/actions.h"
9
10 #include "ardour/dB.h"
11 #include "ardour/monitor_processor.h"
12 #include "ardour/route.h"
13 #include "ardour/utils.h"
14
15 #include "ardour_ui.h"
16 #include "gui_thread.h"
17 #include "monitor_section.h"
18 #include "public_editor.h"
19 #include "utils.h"
20 #include "volume_controller.h"
21
22 #include "i18n.h"
23
24 using namespace ARDOUR;
25 using namespace Gtk;
26 using namespace Gtkmm2ext;
27 using namespace PBD;
28 using namespace std;
29
30 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
31 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::big_knob_pixbuf;
32 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::little_knob_pixbuf;
33
34 MonitorSection::MonitorSection (Session* s)
35         : AxisView (s)
36         , RouteUI (s)
37         , main_table (2, 3)
38         , _tearoff (0)
39         , gain_adjustment (0.781787, 0.0, 1.0, 0.01, 0.1) // initial value is unity gain
40         , gain_control (0)
41         , dim_adjustment (0.2, 0.0, 1.0, 0.01, 0.1) // upper+lower will be reset to match model
42         , dim_control (0)
43         , solo_boost_adjustment (1.0, 1.0, 3.0, 0.01, 0.1)  // upper and lower will be reset to match model
44         , solo_boost_control (0)
45         , solo_cut_adjustment (0.0, 0.0, 1.0, 0.01, 0.1) // upper and lower will be reset to match model
46         , solo_cut_control (0)
47         , solo_in_place_button (solo_model_group, _("SiP"))
48         , afl_button (solo_model_group, _("AFL"))
49         , pfl_button (solo_model_group, _("PFL"))
50         , cut_all_button (_("MUTE"))
51         , dim_all_button (_("dim"))
52         , mono_button (_("mono"))
53         , rude_solo_button (_("soloing"))
54         , rude_iso_button (_("isolated"))
55         , rude_audition_button (_("auditioning"))
56         , exclusive_solo_button (_("Exclusive"))
57         , solo_mute_override_button (_("Solo/Mute"))
58 {
59         Glib::RefPtr<Action> act;
60
61         if (!monitor_actions) {
62
63                 /* do some static stuff */
64
65                 register_actions ();
66
67         }
68         
69         set_session (s);
70
71         VBox* spin_packer;
72         Label* spin_label;
73
74         /* Dim */
75
76         dim_control = new VolumeController (little_knob_pixbuf, &dim_adjustment, false, 30, 30);
77
78         HBox* dim_packer = manage (new HBox);
79         dim_packer->show ();
80
81         spin_label = manage (new Label (_("Dim Cut")));
82         spin_packer = manage (new VBox);
83         spin_packer->show ();
84         spin_packer->set_spacing (6);
85         spin_packer->pack_start (*dim_control, false, false);
86         spin_packer->pack_start (*spin_label, false, false); 
87
88         dim_packer->set_spacing (12);
89         dim_packer->pack_start (*spin_packer, true, true);
90
91         /* Rude Solo */
92
93         rude_solo_button.set_name ("TransportSoloAlert");
94         rude_solo_button.show ();
95
96         rude_iso_button.set_name ("MonitorIsoAlert");
97         rude_iso_button.show ();
98
99         rude_audition_button.set_name ("TransportAuditioningAlert");
100         rude_audition_button.show ();
101
102         ARDOUR_UI::Blink.connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
103
104         rude_solo_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_solo), false);
105         UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
106
107         rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
108         UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
109
110         rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
111         UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
112
113         solo_model_box.set_spacing (6);
114         solo_model_box.pack_start (solo_in_place_button, false, false);
115         solo_model_box.pack_start (afl_button, false, false);
116         solo_model_box.pack_start (pfl_button, false, false);
117
118         solo_in_place_button.show ();
119         afl_button.show ();
120         pfl_button.show ();
121         solo_model_box.show ();
122
123         act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
124         if (act) {
125                 act->connect_proxy (solo_in_place_button);
126         } 
127
128         act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
129         if (act) {
130                 act->connect_proxy (afl_button);
131         } 
132
133         act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
134         if (act) {
135                 act->connect_proxy (pfl_button);
136         } 
137
138         /* Solo Boost */
139
140         solo_boost_control = new VolumeController (little_knob_pixbuf, &solo_boost_adjustment, false, 30, 30);
141
142         HBox* solo_packer = manage (new HBox);
143         solo_packer->set_spacing (12);
144         solo_packer->show ();
145
146         spin_label = manage (new Label (_("Solo Boost")));
147         spin_packer = manage (new VBox);
148         spin_packer->show ();
149         spin_packer->set_spacing (6);
150         spin_packer->pack_start (*solo_boost_control, false, false);
151         spin_packer->pack_start (*spin_label, false, false); 
152
153         solo_packer->pack_start (*spin_packer, true, true);
154
155         /* Solo (SiP) cut */
156
157         solo_cut_control = new VolumeController (little_knob_pixbuf, &solo_cut_adjustment, false, 30, 30);
158
159         spin_label = manage (new Label (_("SiP Cut")));
160         spin_packer = manage (new VBox);
161         spin_packer->show ();
162         spin_packer->set_spacing (6);
163         spin_packer->pack_start (*solo_cut_control, false, false);
164         spin_packer->pack_start (*spin_label, false, false); 
165
166         solo_packer->pack_start (*spin_packer, true, true);
167
168         exclusive_solo_button.set_name (X_("MonitorOptButton"));
169         ARDOUR_UI::instance()->set_tip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
170
171         act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
172         if (act) {
173                 act->connect_proxy (exclusive_solo_button);
174         } 
175
176         solo_mute_override_button.set_name (X_("MonitorOptButton"));
177         ARDOUR_UI::instance()->set_tip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
178         
179         act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
180         if (act) {
181                 act->connect_proxy (solo_mute_override_button);
182         } 
183
184         HBox* solo_opt_box = manage (new HBox);
185         solo_opt_box->set_spacing (12);
186         solo_opt_box->set_homogeneous (true);
187         solo_opt_box->pack_start (exclusive_solo_button);
188         solo_opt_box->pack_start (solo_mute_override_button);
189         solo_opt_box->show ();
190         
191         upper_packer.set_spacing (12);
192
193         Gtk::HBox* rude_box = manage (new HBox);
194         rude_box->pack_start (rude_solo_button, true, true);
195         rude_box->pack_start (rude_iso_button, true, true);
196
197         upper_packer.pack_start (*rude_box, false, false);
198         upper_packer.pack_start (rude_audition_button, false, false);
199         upper_packer.pack_start (solo_model_box, false, false);
200         upper_packer.pack_start (*solo_opt_box, false, false);
201         upper_packer.pack_start (*solo_packer, false, false);
202
203         act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
204         if (act) {
205                 act->connect_proxy (cut_all_button);
206         } 
207
208         act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
209         if (act) {
210                 act->connect_proxy (dim_all_button);
211         } 
212
213         act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
214         if (act) {
215                 act->connect_proxy (mono_button);
216         } 
217
218         cut_all_button.set_name (X_("MonitorMuteButton"));
219         cut_all_button.unset_flags (Gtk::CAN_FOCUS);
220         cut_all_button.set_size_request (50,50);
221         cut_all_button.show ();
222
223         HBox* bbox = manage (new HBox);
224
225         bbox->set_spacing (12);
226         bbox->pack_start (mono_button, true, true);
227         bbox->pack_start (dim_all_button, true, true);
228
229         dim_all_button.set_name (X_("MonitorDimButton"));
230         dim_all_button.unset_flags (Gtk::CAN_FOCUS);
231         mono_button.set_name (X_("MonitorMonoButton"));
232         mono_button.unset_flags (Gtk::CAN_FOCUS);
233
234         lower_packer.set_spacing (12);
235         lower_packer.pack_start (*bbox, false, false);
236         lower_packer.pack_start (cut_all_button, false, false);
237
238         /* Gain */
239
240         gain_control = new VolumeController (big_knob_pixbuf, &gain_adjustment, false, 80, 80);
241
242         spin_label = manage (new Label (_("Gain")));
243         spin_packer = manage (new VBox);
244         spin_packer->show ();
245         spin_packer->set_spacing (6);
246         spin_packer->pack_start (*gain_control, false, false);
247         spin_packer->pack_start (*spin_label, false, false);
248
249         lower_packer.pack_start (*spin_packer, true, true);
250
251         vpacker.set_border_width (12);
252         vpacker.set_spacing (12);
253         vpacker.pack_start (upper_packer, false, false);
254         vpacker.pack_start (*dim_packer, false, false);
255         vpacker.pack_start (main_table, false, false);
256         vpacker.pack_start (lower_packer, false, false);
257
258         hpacker.set_border_width (12);
259         hpacker.set_spacing (12);
260         hpacker.pack_start (vpacker, true, true);
261
262         gain_control->show_all ();
263         dim_control->show_all ();
264         solo_boost_control->show_all ();
265
266         main_table.show ();
267         hpacker.show ();
268         upper_packer.show ();
269         lower_packer.show ();
270         vpacker.show ();
271
272         populate_buttons ();
273         map_state ();
274         assign_controllables ();
275
276         _tearoff = new TearOff (hpacker);
277
278         /* if torn off, make this a normal window */
279         _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
280         _tearoff->tearoff_window().set_title (X_("Monitor"));
281         _tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
282
283         /* catch changes that affect us */
284
285         Config->ParameterChanged.connect (config_connection, invalidator (*this), ui_bind (&MonitorSection::parameter_changed, this, _1), gui_context());
286 }
287
288 MonitorSection::~MonitorSection ()
289 {
290         for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
291                 delete *i;
292         }
293
294         _channel_buttons.clear ();
295
296         delete gain_control;
297         delete dim_control;
298         delete solo_boost_control;
299         delete _tearoff;
300 }
301
302 void
303 MonitorSection::set_session (Session* s)
304 {
305         AxisView::set_session (s);
306
307         if (_session) {
308
309                 _route = _session->monitor_out ();
310
311                 if (_route) {
312                         /* session with control outs */
313                         _monitor = _route->monitor_control ();
314                         assign_controllables ();
315                 } else { 
316                         /* session with no control outs */
317                         _monitor.reset ();
318                         _route.reset ();
319                 }
320                 
321         } else {
322                 /* no session */
323                 _monitor.reset ();
324                 _route.reset ();
325                 control_connections.drop_connections ();
326                 rude_iso_button.set_active (false);
327                 rude_solo_button.set_active (false);
328         }
329
330         /* both might be null */
331 }
332
333 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
334         : cut (X_(""))
335         , dim (X_(""))
336         , solo (X_(""))
337         , invert (X_(""))
338 {
339         cut.set_name (X_("MonitorMuteButton"));
340         dim.set_name (X_("MonitorDimButton"));
341         solo.set_name (X_("MixerSoloButton"));
342         invert.set_name (X_("MonitorInvertButton"));
343
344         gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (cut.gobj()), false);
345         gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (dim.gobj()), false);
346         gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (invert.gobj()), false);
347         gtk_activatable_set_use_action_appearance (GTK_ACTIVATABLE (solo.gobj()), false);
348
349         cut.unset_flags (Gtk::CAN_FOCUS);
350         dim.unset_flags (Gtk::CAN_FOCUS);
351         solo.unset_flags (Gtk::CAN_FOCUS);
352         invert.unset_flags (Gtk::CAN_FOCUS);
353 }
354
355 void
356 MonitorSection::populate_buttons ()
357 {
358         if (!_monitor) {
359                 return;
360         }
361
362         Glib::RefPtr<Action> act;
363         uint32_t nchans = _monitor->output_streams().n_audio();
364         
365         main_table.resize (nchans+1, 5);
366         main_table.set_col_spacings (6);
367         main_table.set_row_spacings (6);
368         main_table.set_homogeneous (true);
369
370         Label* l1 = manage (new Label (X_("out")));
371         main_table.attach (*l1, 0, 1, 0, 1, SHRINK|FILL, SHRINK|FILL);
372         l1 = manage (new Label (X_("cut")));
373         main_table.attach (*l1, 1, 2, 0, 1, SHRINK|FILL, SHRINK|FILL);
374         l1 = manage (new Label (X_("dim")));
375         main_table.attach (*l1, 2, 3, 0, 1, SHRINK|FILL, SHRINK|FILL);
376         l1 = manage (new Label (X_("solo")));
377         main_table.attach (*l1, 3, 4, 0, 1, SHRINK|FILL, SHRINK|FILL);
378         l1 = manage (new Label (X_("inv")));
379         main_table.attach (*l1, 4, 5, 0, 1, SHRINK|FILL, SHRINK|FILL);
380
381         const uint32_t row_offset = 1;
382
383         for (uint32_t i = 0; i < nchans; ++i) {
384                 
385                 string l;
386                 char buf[64];
387
388                 if (nchans == 2) {
389                         if (i == 0) {
390                                 l = "L";
391                         } else {
392                                 l = "R";
393                         }
394                 } else {
395                         char buf[32];
396                         snprintf (buf, sizeof (buf), "%d", i+1);
397                         l = buf;
398                 }
399
400                 Label* label = manage (new Label (l));
401                 main_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
402
403                 ChannelButtonSet* cbs = new ChannelButtonSet;
404
405                 _channel_buttons.push_back (cbs);
406
407                 main_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
408                 main_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL); 
409                 main_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
410                 main_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, SHRINK|FILL, SHRINK|FILL);
411                
412                 snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
413                 act = ActionManager::get_action (X_("Monitor"), buf);
414                 if (act) {
415                         act->connect_proxy (cbs->cut);
416                 } 
417
418                 snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
419                 act = ActionManager::get_action (X_("Monitor"), buf);
420                 if (act) {
421                         act->connect_proxy (cbs->dim);
422                 }
423
424                 snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
425                 act = ActionManager::get_action (X_("Monitor"), buf);
426                 if (act) {
427                         act->connect_proxy (cbs->solo);
428                 }
429
430                 snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
431                 act = ActionManager::get_action (X_("Monitor"), buf);
432                 if (act) {
433                         act->connect_proxy (cbs->invert);
434                 }
435         }
436
437         main_table.show_all ();
438 }
439
440 void 
441 MonitorSection::set_button_names ()
442 {
443         rec_enable_button_label.set_text ("rec");
444         mute_button_label.set_text ("rec");
445         solo_button_label.set_text ("rec");
446 }
447
448 void
449 MonitorSection::toggle_exclusive_solo ()
450 {
451         if (!_monitor) {
452                 return;
453         }
454
455         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
456         if (act) {
457                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
458                 Config->set_exclusive_solo (tact->get_active());
459         }
460
461 }
462
463
464 void
465 MonitorSection::toggle_mute_overrides_solo ()
466 {
467         if (!_monitor) {
468                 return;
469         }
470
471         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
472         if (act) {
473                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
474                 Config->set_solo_mute_override (tact->get_active());
475         }
476 }
477
478 void
479 MonitorSection::dim_all ()
480 {
481         if (!_monitor) {
482                 return;
483         }
484
485         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
486         if (act) {
487                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
488                 _monitor->set_dim_all (tact->get_active());
489         }
490
491 }
492
493 void
494 MonitorSection::cut_all ()
495 {
496         if (!_monitor) {
497                 return;
498         }
499
500         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
501         if (act) {
502                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
503                 _monitor->set_cut_all (tact->get_active());
504         }
505 }
506
507 void
508 MonitorSection::mono ()
509 {
510         if (!_monitor) {
511                 return;
512         }
513
514         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
515         if (act) {
516                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
517                 _monitor->set_mono (tact->get_active());
518         }
519 }
520
521 void
522 MonitorSection::cut_channel (uint32_t chn)
523 {
524         if (!_monitor) {
525                 return;
526         }
527
528         char buf[64];
529         snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
530
531         --chn; // 0-based in backend
532
533         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
534         if (act) {
535                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
536                 _monitor->set_cut (chn, tact->get_active());
537         }
538 }
539
540 void
541 MonitorSection::dim_channel (uint32_t chn)
542 {
543         if (!_monitor) {
544                 return;
545         }
546
547         char buf[64];
548         snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
549
550         --chn; // 0-based in backend
551
552         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
553         if (act) {
554                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
555                 _monitor->set_dim (chn, tact->get_active());
556         }
557
558 }
559
560 void
561 MonitorSection::solo_channel (uint32_t chn)
562 {
563         if (!_monitor) {
564                 return;
565         }
566
567         char buf[64];
568         snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
569
570         --chn; // 0-based in backend
571
572         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
573         if (act) {
574                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
575                 _monitor->set_solo (chn, tact->get_active());
576         }
577
578 }
579
580 void
581 MonitorSection::invert_channel (uint32_t chn)
582 {
583         if (!_monitor) {
584                 return;
585         }
586
587         char buf[64];
588         snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
589
590         --chn; // 0-based in backend
591
592         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
593         if (act) {
594                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
595                 _monitor->set_polarity (chn, tact->get_active());
596         } 
597 }
598
599 void
600 MonitorSection::register_actions ()
601 {
602         string action_name;
603         string action_descr;
604         Glib::RefPtr<Action> act;
605
606         monitor_actions = ActionGroup::create (X_("Monitor"));
607         ActionManager::add_action_group (monitor_actions);
608
609         ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", 
610                                                sigc::mem_fun (*this, &MonitorSection::mono));
611
612         ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", 
613                                                sigc::mem_fun (*this, &MonitorSection::cut_all));
614
615         ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", 
616                                                sigc::mem_fun (*this, &MonitorSection::dim_all));
617
618         act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", 
619                                                sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
620
621         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
622         tact->set_active (Config->get_exclusive_solo());
623
624         act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", 
625                                                      sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
626         
627         tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
628         tact->set_active (Config->get_solo_mute_override());
629
630         /* map from RC config */
631
632
633
634         /* note the 1-based counting (for naming - backend uses 0-based) */
635
636         for (uint32_t chn = 1; chn <= 16; ++chn) {
637
638                 /* for the time being, do not use the action description because it always
639                    shows up in the buttons, which is undesirable.
640                 */
641
642                 action_name = string_compose (X_("monitor-cut-%1"), chn);
643                 action_descr = string_compose (_("Cut Monitor Chn %1"), chn);
644                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", 
645                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
646
647                 action_name = string_compose (X_("monitor-dim-%1"), chn);
648                 action_descr = string_compose (_("Dim Monitor Chn %1"), chn+1);
649                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", 
650                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
651
652                 action_name = string_compose (X_("monitor-solo-%1"), chn);
653                 action_descr = string_compose (_("Solo Monitor Chn %1"), chn);
654                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", 
655                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
656
657                 action_name = string_compose (X_("monitor-invert-%1"), chn);
658                 action_descr = string_compose (_("Invert Monitor Chn %1"), chn);
659                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", 
660                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
661
662         }
663
664
665         Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
666         RadioAction::Group solo_group;
667
668         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "",
669                                               sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
670         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "",
671                                               sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
672         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "",
673                                               sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
674
675         ActionManager::add_action_group (solo_actions);
676 }
677
678 void
679 MonitorSection::solo_use_in_place ()
680 {
681         /* this is driven by a toggle on a radio group, and so is invoked twice,
682            once for the item that became inactive and once for the one that became
683            active.
684         */
685
686         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
687
688         if (act) {
689                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
690                 if (ract) {
691                         Config->set_solo_control_is_listen_control (!ract->get_active());
692                 }
693         }
694 }
695
696 void
697 MonitorSection::solo_use_afl ()
698 {
699         /* this is driven by a toggle on a radio group, and so is invoked twice,
700            once for the item that became inactive and once for the one that became
701            active.
702         */
703         
704         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
705         if (act) {
706                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
707                 if (ract) {
708                         if (ract->get_active()) {
709                                 Config->set_listen_position (AfterFaderListen);
710                                 Config->set_solo_control_is_listen_control (true);
711                         }
712                 }
713         }
714 }
715
716 void
717 MonitorSection::solo_use_pfl ()
718 {
719         /* this is driven by a toggle on a radio group, and so is invoked twice,
720            once for the item that became inactive and once for the one that became
721            active.
722         */
723
724         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
725         if (act) {
726                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
727                 if (ract) {
728                         if (ract->get_active()) {
729                                 Config->set_listen_position (PreFaderListen);
730                                 Config->set_solo_control_is_listen_control (true);
731                         }
732                 }
733         }
734 }
735
736 void
737 MonitorSection::setup_knob_images ()
738 {
739         try {
740                 
741                 big_knob_pixbuf = ::get_icon ("bigknob");
742                 
743         }  catch (...) {
744                 
745                 error << "No knob image found (or not loadable) at "
746                       << " .... "
747                       << endmsg;
748                 throw failed_constructor ();
749         }
750         
751         try {
752                 
753                 little_knob_pixbuf = ::get_icon ("littleknob");
754                 
755         }  catch (...) {
756                 
757                 error << "No knob image found (or not loadable) at "
758                       << " .... "
759                       << endmsg;
760                 throw failed_constructor ();
761         }
762 }
763
764 bool
765 MonitorSection::nonlinear_gain_printer (SpinButton* button)
766 {
767         double val = button->get_adjustment()->get_value();
768         char buf[16];
769         snprintf (buf, sizeof (buf), "%.1f", accurate_coefficient_to_dB (slider_position_to_gain (val)));
770         button->set_text (buf);
771         return true;
772 }
773
774 bool
775 MonitorSection::linear_gain_printer (SpinButton* button)
776 {
777         double val = button->get_adjustment()->get_value();
778         char buf[16];
779         snprintf (buf, sizeof (buf), "%.1f", accurate_coefficient_to_dB (val));
780         button->set_text (buf);
781         return true;
782 }
783
784 void
785 MonitorSection::update_solo_model ()
786 {
787         const char* action_name;
788         Glib::RefPtr<Action> act;
789
790         if (Config->get_solo_control_is_listen_control()) {
791                 switch (Config->get_listen_position()) {
792                 case AfterFaderListen:
793                         action_name = X_("solo-use-afl");
794                         break;
795                 case PreFaderListen:
796                         action_name = X_("solo-use-pfl");
797                         break;
798                 }
799         } else {
800                 action_name = X_("solo-use-in-place");
801         }
802
803         act = ActionManager::get_action (X_("Solo"), action_name);
804         if (act) {
805                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
806                 if (ract) {
807                         ract->set_active (true);
808                 }
809         }
810 }
811
812 void
813 MonitorSection::map_state ()
814 {
815         if (!_route || !_monitor) {
816                 return;
817         }
818
819         gain_control->get_adjustment()->set_value (gain_to_slider_position (_route->gain_control()->get_value()));
820         dim_control->get_adjustment()->set_value (_monitor->dim_level());
821         solo_boost_control->get_adjustment()->set_value (_monitor->solo_boost_level());
822
823         Glib::RefPtr<Action> act;
824
825         update_solo_model ();
826         
827         act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
828         if (act) {
829                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
830                 if (tact) {
831                         tact->set_active (_monitor->cut_all());
832                 }
833         }
834
835         act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
836         if (act) {
837                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
838                 if (tact) {
839                         tact->set_active (_monitor->dim_all());
840                 }
841         }
842         
843         act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
844         if (act) {
845                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
846                 if (tact) {
847                         tact->set_active (_monitor->mono());
848                 }
849         }
850
851         uint32_t nchans = _monitor->output_streams().n_audio();
852
853         assert (nchans == _channel_buttons.size ());
854
855         for (uint32_t n = 0; n < nchans; ++n) {
856
857                 char action_name[32];
858
859                 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n+1);
860                 act = ActionManager::get_action (X_("Monitor"), action_name);
861                 if (act) {
862                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
863                         if (tact) {
864                                 tact->set_active (_monitor->cut (n));
865                         }
866                 }
867
868                 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n+1);
869                 act = ActionManager::get_action (X_("Monitor"), action_name);
870                 if (act) {
871                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
872                         if (tact) {
873                                 tact->set_active (_monitor->dimmed (n));
874                         }
875                 }
876
877                 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n+1);
878                 act = ActionManager::get_action (X_("Monitor"), action_name);
879                 if (act) {
880                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
881                         if (tact) {
882                                 tact->set_active (_monitor->soloed (n));
883                         }
884                 }
885
886                 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n+1);
887                 act = ActionManager::get_action (X_("Monitor"), action_name);
888                 if (act) {
889                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
890                         if (tact) {
891                                 tact->set_active (_monitor->inverted (n));
892                         }
893                 }
894         }
895 }
896
897 void
898 MonitorSection::do_blink (bool onoff)
899 {
900         solo_blink (onoff);
901         audition_blink (onoff);
902 }
903
904 void
905 MonitorSection::audition_blink (bool onoff)
906 {
907         if (_session == 0) {
908                 return;
909         }
910
911         if (_session->is_auditioning()) {
912                 if (onoff) {
913                         rude_audition_button.set_state (STATE_ACTIVE);
914                 } else {
915                         rude_audition_button.set_state (STATE_NORMAL);
916                 }
917         } else {
918                 rude_audition_button.set_active (false);
919                 rude_audition_button.set_state (STATE_NORMAL);
920         }
921 }
922
923 void
924 MonitorSection::solo_blink (bool onoff)
925 {
926         if (_session == 0) {
927                 return;
928         }
929
930         if (_session->soloing() || _session->listening()) {
931                 if (onoff) {
932                         rude_solo_button.set_state (STATE_ACTIVE);
933                 } else {
934                         rude_solo_button.set_state (STATE_NORMAL);
935                 }
936
937                 if (_session->soloing()) {
938                         rude_iso_button.set_active (_session->solo_isolated());
939                 }
940
941         } else {
942                 // rude_solo_button.set_active (false);
943                 rude_solo_button.set_state (STATE_NORMAL);
944                 rude_iso_button.set_active (false);
945         }
946 }
947
948 bool
949 MonitorSection::cancel_solo (GdkEventButton* ev)
950 {
951         if (_session) {
952                 if (_session->soloing()) {
953                         _session->set_solo (_session->get_routes(), false);
954                 } else if (_session->listening()) {
955                         _session->set_listen (_session->get_routes(), false);
956                 }
957         }
958
959         return true;
960 }
961
962 bool
963 MonitorSection::cancel_isolate (GdkEventButton* ev)
964 {
965         if (_session) {
966                 boost::shared_ptr<RouteList> rl (_session->get_routes ());
967                 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
968         }
969
970         return true;
971 }
972
973 bool
974 MonitorSection::cancel_audition (GdkEventButton* ev)
975 {
976         if (_session) {
977                 _session->cancel_audition();
978         }
979         return true;
980 }
981
982 void
983 MonitorSection::solo_cut_changed ()
984 {
985         Config->set_solo_mute_gain (slider_position_to_gain (solo_cut_adjustment.get_value()));
986 }
987
988 void
989 MonitorSection::parameter_changed (std::string name)
990 {
991         if (name == "solo-control-is-listen-control" ||
992             name == "listen-position") {
993                 update_solo_model ();
994         } else if (name == "solo-mute-gain") {
995                 solo_cut_adjustment.set_value (gain_to_slider_position (Config->get_solo_mute_gain()));
996         }
997 }
998
999 void
1000 MonitorSection::assign_controllables ()
1001 {
1002         boost::shared_ptr<Controllable> none;
1003
1004         if (!gain_control) {
1005                 /* too early - GUI controls not set up yet */
1006                 return;
1007         }
1008
1009         if (_route) {
1010                 gain_control->set_controllable (_route->gain_control());
1011                 control_link (control_connections, _route->gain_control(), gain_adjustment);
1012         } else {
1013                 gain_control->set_controllable (none);
1014         }
1015
1016         if (_monitor) {
1017
1018                 cut_all_button.set_controllable (_monitor->cut_control());
1019                 cut_all_button.watch ();
1020                 dim_all_button.set_controllable (_monitor->dim_control());
1021                 dim_all_button.watch ();
1022                 mono_button.set_controllable (_monitor->mono_control());
1023                 mono_button.watch ();
1024
1025                 boost::shared_ptr<Controllable> c (_monitor->dim_level_control ());
1026
1027                 dim_control->set_controllable (c);
1028                 dim_adjustment.set_lower (c->lower());
1029                 dim_adjustment.set_upper (c->upper());
1030                 control_link (control_connections, c, dim_adjustment);
1031                 
1032                 c = _monitor->solo_boost_control ();
1033                 solo_boost_control->set_controllable (c);
1034                 solo_boost_adjustment.set_lower (c->lower());
1035                 solo_boost_adjustment.set_upper (c->upper());
1036                 control_link (control_connections, c, solo_boost_adjustment);
1037
1038         } else {
1039
1040                 cut_all_button.set_controllable (none);
1041                 dim_all_button.set_controllable (none);
1042                 mono_button.set_controllable (none);
1043
1044                 dim_control->set_controllable (none);
1045                 solo_boost_control->set_controllable (none);
1046         }
1047 }