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