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