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