Remove over 500 unnecessary includes (including 54 of session.h).
[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/monitor_processor.h"
12 #include "ardour/route.h"
13
14 #include "ardour_ui.h"
15 #include "gui_thread.h"
16 #include "monitor_section.h"
17 #include "public_editor.h"
18 #include "volume_controller.h"
19 #include "utils.h"
20
21 #include "i18n.h"
22
23 using namespace ARDOUR;
24 using namespace Gtk;
25 using namespace Gtkmm2ext;
26 using namespace PBD;
27 using namespace std;
28
29 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
30 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::big_knob_pixbuf;
31 Glib::RefPtr<Gdk::Pixbuf> MonitorSection::little_knob_pixbuf;
32
33 MonitorSection::MonitorSection (Session* s)
34         : AxisView (s)
35         , RouteUI (s)
36         , _tearoff (0)
37         , channel_table_viewport (*channel_table_scroller.get_hadjustment(),
38                                   *channel_table_scroller.get_vadjustment ())
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         channel_table_scroller.add (channel_table_viewport);
261
262         channel_size_group  = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
263         channel_size_group->add_widget (channel_table_header);
264         channel_size_group->add_widget (channel_table);
265
266         channel_table_header.resize (1, 5);
267         Label* l1 = manage (new Label (X_("out")));
268         l1->set_name (X_("MonitorSectionLabel"));
269         channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
270         l1 = manage (new Label (X_("mute")));
271         l1->set_name (X_("MonitorSectionLabel"));
272         channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
273         l1 = manage (new Label (X_("dim")));
274         l1->set_name (X_("MonitorSectionLabel"));
275         channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
276         l1 = manage (new Label (X_("solo")));
277         l1->set_name (X_("MonitorSectionLabel"));
278         channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
279         l1 = manage (new Label (X_("inv")));
280         l1->set_name (X_("MonitorSectionLabel"));
281         channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
282         channel_table_header.show ();
283
284         table_hpacker.pack_start (channel_table, true, true);
285
286         /* note that we don't pack the table_hpacker till later
287          */
288
289         vpacker.set_border_width (6);
290         vpacker.set_spacing (12);
291         vpacker.pack_start (upper_packer, false, false);
292         vpacker.pack_start (*dim_packer, false, false);
293         vpacker.pack_start (channel_table_header, false, false);
294         vpacker.pack_start (channel_table_packer, false, false);
295         vpacker.pack_start (lower_packer, false, false);
296
297         hpacker.pack_start (vpacker, true, true);
298
299         gain_control->show_all ();
300         dim_control->show_all ();
301         solo_boost_control->show_all ();
302
303         channel_table.show ();
304         hpacker.show ();
305         upper_packer.show ();
306         lower_packer.show ();
307         vpacker.show ();
308
309         populate_buttons ();
310         map_state ();
311         assign_controllables ();
312
313         _tearoff = new TearOff (hpacker);
314
315         /* if torn off, make this a normal window */
316         _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
317         _tearoff->tearoff_window().set_title (X_("Monitor"));
318         _tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
319
320         /* catch changes that affect us */
321
322         Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
323 }
324
325 MonitorSection::~MonitorSection ()
326 {
327         for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
328                 delete *i;
329         }
330
331         _channel_buttons.clear ();
332
333         delete gain_control;
334         delete dim_control;
335         delete solo_boost_control;
336         delete _tearoff;
337 }
338
339 void
340 MonitorSection::set_session (Session* s)
341 {
342         AxisView::set_session (s);
343
344         if (_session) {
345
346                 _route = _session->monitor_out ();
347
348                 if (_route) {
349                         /* session with monitor section */
350                         _monitor = _route->monitor_control ();
351                         assign_controllables ();
352                 } else {
353                         /* session with no monitor section */
354                         _monitor.reset ();
355                         _route.reset ();
356                 }
357
358                 if (channel_table_scroller.get_parent()) {
359                         /* scroller is packed, so remove it */
360                         channel_table_packer.remove (channel_table_scroller);
361                 } 
362
363                 if (table_hpacker.get_parent () == &channel_table_packer) {
364                         /* this occurs when the table hpacker is directly
365                            packed, so remove it.
366                         */
367                         channel_table_packer.remove (table_hpacker);
368                 } else if (table_hpacker.get_parent()) {
369                         channel_table_viewport.remove ();
370                 }
371                 
372                 if (_monitor->output_streams().n_audio() > 7) {
373                         /* put the table into a scrolled window, and then put
374                          * that into the channel vpacker, after the table header
375                          */
376                         channel_table_viewport.add (table_hpacker);
377                         channel_table_packer.pack_start (channel_table_scroller, true, true);
378                         channel_table_viewport.show ();
379                         channel_table_scroller.show ();
380
381                 } else {
382                         /* just put the channel table itself into the channel
383                          * vpacker, after the table header
384                          */
385                          
386                         channel_table_packer.pack_start (table_hpacker, true, true);
387                         channel_table_scroller.hide ();
388                 }
389
390                 table_hpacker.show ();
391                 channel_table.show ();
392
393         } else {
394                 /* no session */
395
396                 _monitor.reset ();
397                 _route.reset ();
398                 control_connections.drop_connections ();
399                 rude_iso_button.unset_active_state ();
400                 rude_solo_button.unset_active_state ();
401
402                 assign_controllables ();
403         }
404 }
405
406 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
407 {
408         cut.set_diameter (3);
409         dim.set_diameter (3);
410         solo.set_diameter (3);
411         invert.set_diameter (3);
412
413         cut.set_name (X_("monitor section cut"));
414         dim.set_name (X_("monitor section dim"));
415         solo.set_name (X_("monitor section solo"));
416         invert.set_name (X_("monitor section invert"));
417
418         cut.unset_flags (Gtk::CAN_FOCUS);
419         dim.unset_flags (Gtk::CAN_FOCUS);
420         solo.unset_flags (Gtk::CAN_FOCUS);
421         invert.unset_flags (Gtk::CAN_FOCUS);
422 }
423
424 void
425 MonitorSection::populate_buttons ()
426 {
427         if (!_monitor) {
428                 return;
429         }
430
431         Glib::RefPtr<Action> act;
432         uint32_t nchans = _monitor->output_streams().n_audio();
433
434         channel_table.resize (nchans, 5);
435         channel_table.set_col_spacings (6);
436         channel_table.set_row_spacings (6);
437         channel_table.set_homogeneous (true);
438
439         const uint32_t row_offset = 0;
440
441         for (uint32_t i = 0; i < nchans; ++i) {
442
443                 string l;
444                 char buf[64];
445
446                 if (nchans == 2) {
447                         if (i == 0) {
448                                 l = "L";
449                         } else {
450                                 l = "R";
451                         }
452                 } else {
453                         char buf[32];
454                         snprintf (buf, sizeof (buf), "%d", i+1);
455                         l = buf;
456                 }
457
458                 Label* label = manage (new Label (l));
459                 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
460
461                 ChannelButtonSet* cbs = new ChannelButtonSet;
462
463                 _channel_buttons.push_back (cbs);
464
465                 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
466                 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
467                 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
468                 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
469
470                 snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
471                 act = ActionManager::get_action (X_("Monitor"), buf);
472                 if (act) {
473                         cbs->cut.set_related_action (act);
474                 }
475
476                 snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
477                 act = ActionManager::get_action (X_("Monitor"), buf);
478                 if (act) {
479                         cbs->dim.set_related_action (act);
480                 }
481
482                 snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
483                 act = ActionManager::get_action (X_("Monitor"), buf);
484                 if (act) {
485                         cbs->solo.set_related_action (act);
486                 }
487
488                 snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
489                 act = ActionManager::get_action (X_("Monitor"), buf);
490                 if (act) {
491                         cbs->invert.set_related_action (act);
492                 }
493         }
494
495         channel_table.show_all ();
496 }
497
498 void
499 MonitorSection::toggle_exclusive_solo ()
500 {
501         if (!_monitor) {
502                 return;
503         }
504
505         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
506         if (act) {
507                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
508                 Config->set_exclusive_solo (tact->get_active());
509         }
510
511 }
512
513
514 void
515 MonitorSection::toggle_mute_overrides_solo ()
516 {
517         if (!_monitor) {
518                 return;
519         }
520
521         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
522         if (act) {
523                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
524                 Config->set_solo_mute_override (tact->get_active());
525         }
526 }
527
528 void
529 MonitorSection::dim_all ()
530 {
531         if (!_monitor) {
532                 return;
533         }
534
535         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
536         if (act) {
537                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
538                 _monitor->set_dim_all (tact->get_active());
539         }
540
541 }
542
543 void
544 MonitorSection::cut_all ()
545 {
546         if (!_monitor) {
547                 return;
548         }
549
550         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
551         if (act) {
552                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
553                 _monitor->set_cut_all (tact->get_active());
554         }
555 }
556
557 void
558 MonitorSection::mono ()
559 {
560         if (!_monitor) {
561                 return;
562         }
563
564         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
565         if (act) {
566                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
567                 _monitor->set_mono (tact->get_active());
568         }
569 }
570
571 void
572 MonitorSection::cut_channel (uint32_t chn)
573 {
574         if (!_monitor) {
575                 return;
576         }
577
578         char buf[64];
579         snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
580
581         --chn; // 0-based in backend
582
583         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
584         if (act) {
585                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
586                 _monitor->set_cut (chn, tact->get_active());
587         }
588 }
589
590 void
591 MonitorSection::dim_channel (uint32_t chn)
592 {
593         if (!_monitor) {
594                 return;
595         }
596
597         char buf[64];
598         snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
599
600         --chn; // 0-based in backend
601
602         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
603         if (act) {
604                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
605                 _monitor->set_dim (chn, tact->get_active());
606         }
607
608 }
609
610 void
611 MonitorSection::solo_channel (uint32_t chn)
612 {
613         if (!_monitor) {
614                 return;
615         }
616
617         char buf[64];
618         snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
619
620         --chn; // 0-based in backend
621
622         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
623         if (act) {
624                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
625                 _monitor->set_solo (chn, tact->get_active());
626         }
627
628 }
629
630 void
631 MonitorSection::invert_channel (uint32_t chn)
632 {
633         if (!_monitor) {
634                 return;
635         }
636
637         char buf[64];
638         snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
639
640         --chn; // 0-based in backend
641
642         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
643         if (act) {
644                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
645                 _monitor->set_polarity (chn, tact->get_active());
646         }
647 }
648
649 void
650 MonitorSection::register_actions ()
651 {
652         string action_name;
653         string action_descr;
654         Glib::RefPtr<Action> act;
655
656         monitor_actions = ActionGroup::create (X_("Monitor"));
657         ActionManager::add_action_group (monitor_actions);
658
659         ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", "Switch monitor to mono",
660                                                sigc::mem_fun (*this, &MonitorSection::mono));
661
662         ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", "Cut monitor",
663                                                sigc::mem_fun (*this, &MonitorSection::cut_all));
664
665         ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", "Dim monitor",
666                                                sigc::mem_fun (*this, &MonitorSection::dim_all));
667
668         act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", "Toggle exclusive solo mode",
669                                                sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
670
671         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
672         tact->set_active (Config->get_exclusive_solo());
673
674         act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", "Toggle mute overrides solo mode",
675                                                      sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
676
677         tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
678         tact->set_active (Config->get_solo_mute_override());
679
680
681         /* note the 1-based counting (for naming - backend uses 0-based) */
682
683         for (uint32_t chn = 1; chn <= 16; ++chn) {
684
685                 action_name = string_compose (X_("monitor-cut-%1"), chn);
686                 action_descr = string_compose (_("Cut monitor channel %1"), chn);
687                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
688                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
689
690                 action_name = string_compose (X_("monitor-dim-%1"), chn);
691                 action_descr = string_compose (_("Dim monitor channel %1"), chn+1);
692                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
693                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
694
695                 action_name = string_compose (X_("monitor-solo-%1"), chn);
696                 action_descr = string_compose (_("Solo monitor channel %1"), chn+1);
697                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
698                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
699
700                 action_name = string_compose (X_("monitor-invert-%1"), chn);
701                 action_descr = string_compose (_("Invert monitor channel %1"), chn+1);
702                 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
703                                                        sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
704
705         }
706
707
708         Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
709         RadioAction::Group solo_group;
710
711         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", "In-place solo",
712                                               sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
713         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", "After Fade Listen (AFL) solo",
714                                               sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
715         ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", "Pre Fade Listen (PFL) solo",
716                                               sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
717
718         ActionManager::add_action_group (solo_actions);
719 }
720
721 void
722 MonitorSection::solo_use_in_place ()
723 {
724         /* this is driven by a toggle on a radio group, and so is invoked twice,
725            once for the item that became inactive and once for the one that became
726            active.
727         */
728
729         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
730
731         if (act) {
732                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
733                 if (ract) {
734                         if (!ract->get_active ()) {
735                                 /* We are turning SiP off, which means that AFL or PFL will be turned on
736                                    shortly; don't update the solo model in the mean time, as if the currently
737                                    configured listen position is not the one that is about to be turned on,
738                                    things will go wrong.
739                                 */
740                                 _inhibit_solo_model_update = true;
741                         }
742                         Config->set_solo_control_is_listen_control (!ract->get_active());
743                         _inhibit_solo_model_update = false;
744                 }
745         }
746 }
747
748 void
749 MonitorSection::solo_use_afl ()
750 {
751         /* this is driven by a toggle on a radio group, and so is invoked twice,
752            once for the item that became inactive and once for the one that became
753            active.
754         */
755
756         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
757         if (act) {
758                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
759                 if (ract) {
760                         if (ract->get_active()) {
761                                 Config->set_solo_control_is_listen_control (true);
762                                 Config->set_listen_position (AfterFaderListen);
763                         }
764                 }
765         }
766 }
767
768 void
769 MonitorSection::solo_use_pfl ()
770 {
771         /* this is driven by a toggle on a radio group, and so is invoked twice,
772            once for the item that became inactive and once for the one that became
773            active.
774         */
775
776         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
777         if (act) {
778                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
779                 if (ract) {
780                         if (ract->get_active()) {
781                                 Config->set_solo_control_is_listen_control (true);
782                                 Config->set_listen_position (PreFaderListen);
783                         }
784                 }
785         }
786 }
787
788 void
789 MonitorSection::setup_knob_images ()
790 {
791         
792         try {
793                 uint32_t c = ARDOUR_UI::config()->color_by_name ("monitor knob");
794                 char buf[16];
795                 snprintf (buf, 16, "#%x", (c >> 8));
796                 MotionFeedback::set_lamp_color (buf);
797                 big_knob_pixbuf = MotionFeedback::render_pixbuf (80);
798
799         }  catch (...) {
800
801                 error << "No usable large knob image" << endmsg;
802                 throw failed_constructor ();
803         }
804
805         if (!big_knob_pixbuf) {
806                 error << "No usable large knob image" << endmsg;
807                 throw failed_constructor ();
808         }
809
810         try {
811
812                 little_knob_pixbuf = MotionFeedback::render_pixbuf (30);
813
814         }  catch (...) {
815
816                 error << "No usable small knob image" << endmsg;
817                 throw failed_constructor ();
818         }
819
820         if (!little_knob_pixbuf) {
821                 error << "No usable small knob image" << endmsg;
822                 throw failed_constructor ();
823         }
824
825 }
826
827 void
828 MonitorSection::update_solo_model ()
829 {
830         if (_inhibit_solo_model_update) {
831                 return;
832         }
833         
834         const char* action_name = 0;
835         Glib::RefPtr<Action> act;
836
837         if (Config->get_solo_control_is_listen_control()) {
838                 switch (Config->get_listen_position()) {
839                 case AfterFaderListen:
840                         action_name = X_("solo-use-afl");
841                         break;
842                 case PreFaderListen:
843                         action_name = X_("solo-use-pfl");
844                         break;
845                 }
846         } else {
847                 action_name = X_("solo-use-in-place");
848         }
849
850         act = ActionManager::get_action (X_("Solo"), action_name);
851         if (act) {
852
853                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
854                 if (ract) {
855                         /* because these are radio buttons, one of them will be
856                            active no matter what. to trigger a change in the
857                            action so that the view picks it up, toggle it.
858                         */
859                         if (ract->get_active()) {
860                                 ract->set_active (false);
861                         }
862                         ract->set_active (true);
863                 }
864                 
865         }
866 }
867
868 void
869 MonitorSection::map_state ()
870 {
871         if (!_route || !_monitor) {
872                 return;
873         }
874
875         Glib::RefPtr<Action> act;
876
877         update_solo_model ();
878
879         act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
880         if (act) {
881                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
882                 if (tact) {
883                         tact->set_active (_monitor->cut_all());
884                 }
885         }
886
887         act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
888         if (act) {
889                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
890                 if (tact) {
891                         tact->set_active (_monitor->dim_all());
892                 }
893         }
894
895         act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
896         if (act) {
897                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
898                 if (tact) {
899                         tact->set_active (_monitor->mono());
900                 }
901         }
902
903         uint32_t nchans = _monitor->output_streams().n_audio();
904
905         assert (nchans == _channel_buttons.size ());
906
907         for (uint32_t n = 0; n < nchans; ++n) {
908
909                 char action_name[32];
910
911                 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n+1);
912                 act = ActionManager::get_action (X_("Monitor"), action_name);
913                 if (act) {
914                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
915                         if (tact) {
916                                 tact->set_active (_monitor->cut (n));
917                         }
918                 }
919
920                 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n+1);
921                 act = ActionManager::get_action (X_("Monitor"), action_name);
922                 if (act) {
923                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
924                         if (tact) {
925                                 tact->set_active (_monitor->dimmed (n));
926                         }
927                 }
928
929                 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n+1);
930                 act = ActionManager::get_action (X_("Monitor"), action_name);
931                 if (act) {
932                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
933                         if (tact) {
934                                 tact->set_active (_monitor->soloed (n));
935                         }
936                 }
937
938                 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n+1);
939                 act = ActionManager::get_action (X_("Monitor"), action_name);
940                 if (act) {
941                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
942                         if (tact) {
943                                 tact->set_active (_monitor->inverted (n));
944                         }
945                 }
946         }
947 }
948
949 void
950 MonitorSection::do_blink (bool onoff)
951 {
952         solo_blink (onoff);
953         audition_blink (onoff);
954 }
955
956 void
957 MonitorSection::audition_blink (bool onoff)
958 {
959         if (_session == 0) {
960                 return;
961         }
962
963         if (_session->is_auditioning()) {
964                 rude_audition_button.set_active (onoff);
965         } else {
966                 rude_audition_button.set_active (false);
967         }
968 }
969
970 void
971 MonitorSection::solo_blink (bool onoff)
972 {
973         if (_session == 0) {
974                 return;
975         }
976
977         if (_session->soloing() || _session->listening()) {
978                 rude_solo_button.set_active (onoff);
979
980                 if (_session->soloing()) {
981                         if (_session->solo_isolated()) {
982                                 rude_iso_button.set_active (false);
983                         }
984                 }
985
986         } else {
987                 rude_solo_button.set_active (false);
988                 rude_iso_button.set_active (false);
989         }
990 }
991
992 bool
993 MonitorSection::cancel_solo (GdkEventButton*)
994 {
995         if (_session) {
996                 if (_session->soloing()) {
997                         _session->set_solo (_session->get_routes(), false);
998                 } else if (_session->listening()) {
999                         _session->set_listen (_session->get_routes(), false);
1000                 }
1001         }
1002
1003         return true;
1004 }
1005
1006 bool
1007 MonitorSection::cancel_isolate (GdkEventButton*)
1008 {
1009         if (_session) {
1010                 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1011                 _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
1012         }
1013
1014         return true;
1015 }
1016
1017 bool
1018 MonitorSection::cancel_audition (GdkEventButton*)
1019 {
1020         if (_session) {
1021                 _session->cancel_audition();
1022         }
1023         return true;
1024 }
1025
1026 void
1027 MonitorSection::parameter_changed (std::string name)
1028 {
1029         if (name == "solo-control-is-listen-control") {
1030                 update_solo_model ();
1031         } else if (name == "listen-position") {
1032                 update_solo_model ();
1033         }
1034 }
1035
1036 void
1037 MonitorSection::assign_controllables ()
1038 {
1039         boost::shared_ptr<Controllable> none;
1040
1041         if (!gain_control) {
1042                 /* too early - GUI controls not set up yet */
1043                 return;
1044         }
1045
1046         if (_session) {
1047                 solo_cut_control->set_controllable (_session->solo_cut_control());
1048         } else {
1049                 solo_cut_control->set_controllable (none);
1050         }
1051
1052         if (_route) {
1053                 gain_control->set_controllable (_route->gain_control());
1054         } else {
1055                 gain_control->set_controllable (none);
1056         }
1057
1058         if (_monitor) {
1059
1060                 cut_all_button.set_controllable (_monitor->cut_control());
1061                 cut_all_button.watch ();
1062                 dim_all_button.set_controllable (_monitor->dim_control());
1063                 dim_all_button.watch ();
1064                 mono_button.set_controllable (_monitor->mono_control());
1065                 mono_button.watch ();
1066
1067                 dim_control->set_controllable (_monitor->dim_level_control ());
1068                 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1069
1070         } else {
1071
1072                 cut_all_button.set_controllable (none);
1073                 dim_all_button.set_controllable (none);
1074                 mono_button.set_controllable (none);
1075
1076                 dim_control->set_controllable (none);
1077                 solo_boost_control->set_controllable (none);
1078         }
1079 }
1080
1081 string
1082 MonitorSection::state_id() const
1083 {
1084         return "monitor-section";
1085 }