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