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