297aa04288225dd648ae3c5e1539457ce7a71c39
[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 #include "pbd/replace_all.h"
25
26 #include "gtkmm2ext/bindable_button.h"
27 #include "gtkmm2ext/tearoff.h"
28 #include "gtkmm2ext/actions.h"
29 #include "gtkmm2ext/utils.h"
30
31 #include <gtkmm/menu.h>
32 #include <gtkmm/menuitem.h>
33
34 #include "ardour/amp.h"
35 #include "ardour/audioengine.h"
36 #include "ardour/monitor_processor.h"
37 #include "ardour/port.h"
38 #include "ardour/route.h"
39 #include "ardour/user_bundle.h"
40 #include "ardour/plugin_manager.h"
41
42 #include "gui_thread.h"
43 #include "monitor_section.h"
44 #include "public_editor.h"
45 #include "timers.h"
46 #include "tooltips.h"
47 #include "ui_config.h"
48 #include "utils.h"
49
50 #include "i18n.h"
51
52 using namespace ARDOUR;
53 using namespace ARDOUR_UI_UTILS;
54 using namespace Gtk;
55 using namespace Gtkmm2ext;
56 using namespace PBD;
57 using namespace std;
58
59 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
60
61 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
62
63 MonitorSection::MonitorSection (Session* s)
64         : AxisView (s)
65         , RouteUI (s)
66         , _tearoff (0)
67         , channel_table_viewport (*channel_table_scroller.get_hadjustment()
68         , *channel_table_scroller.get_vadjustment ())
69         , gain_control (0)
70         , dim_control (0)
71         , solo_boost_control (0)
72         , solo_cut_control (0)
73         , gain_display (0)
74         , dim_display (0)
75         , solo_boost_display (0)
76         , solo_cut_display (0)
77         , _output_selector (0)
78         , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
79         , afl_button (_("AFL"), ArdourButton::led_default_elements)
80         , pfl_button (_("PFL"), ArdourButton::led_default_elements)
81         , exclusive_solo_button (ArdourButton::led_default_elements)
82         , solo_mute_override_button (ArdourButton::led_default_elements)
83         , toggle_processorbox_button (ArdourButton::default_elements)
84         , _inhibit_solo_model_update (false)
85         , _ui_initialized (false)
86         , myactions (X_("monitor section"))
87         , bindings (0)
88 {
89
90         using namespace Menu_Helpers;
91
92         Glib::RefPtr<Action> act;
93
94         if (!monitor_actions) {
95                 register_actions ();
96                 load_bindings ();
97         }
98
99         _plugin_selector = new PluginSelector (PluginManager::instance());
100         insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
101         insert_box->set_no_show_all ();
102         insert_box->show ();
103         // TODO allow keyboard shortcuts in ProcessorBox
104
105         set_session (s);
106
107         /* Rude Solo  & Solo Isolated */
108         rude_solo_button.set_text (_("Soloing"));
109         rude_solo_button.set_name ("rude solo");
110         rude_solo_button.show ();
111
112         rude_iso_button.set_text (_("Isolated"));
113         rude_iso_button.set_name ("rude isolate");
114         rude_iso_button.show ();
115
116         rude_audition_button.set_text (_("Auditioning"));
117         rude_audition_button.set_name ("rude audition");
118         rude_audition_button.show ();
119
120         Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
121
122         act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
123         rude_solo_button.set_related_action (act);
124         UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
125
126         rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
127         UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
128
129         rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
130         UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
131
132         /* SIP, AFL, PFL radio */
133
134         solo_in_place_button.set_name ("monitor section solo model");
135         afl_button.set_name ("monitor section solo model");
136         pfl_button.set_name ("monitor section solo model");
137
138         solo_in_place_button.set_led_left (true);
139         afl_button.set_led_left (true);
140         pfl_button.set_led_left (true);
141
142         solo_in_place_button.show ();
143         afl_button.show ();
144         pfl_button.show ();
145
146         act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
147         set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
148         if (act) {
149                 solo_in_place_button.set_related_action (act);
150         }
151
152         act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
153         set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
154         if (act) {
155                 afl_button.set_related_action (act);
156         }
157
158         act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
159         set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
160         if (act) {
161                 pfl_button.set_related_action (act);
162         }
163
164         /* Solo option buttons */
165         exclusive_solo_button.set_text (_("Excl. Solo"));
166         exclusive_solo_button.set_name (X_("monitor section solo option"));
167         set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
168
169         act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
170         if (act) {
171                 exclusive_solo_button.set_related_action (act);
172         }
173
174         solo_mute_override_button.set_text (_("Solo ยป Mute"));
175         solo_mute_override_button.set_name (X_("monitor section solo option"));
176         set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
177
178         act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
179         if (act) {
180                 solo_mute_override_button.set_related_action (act);
181         }
182
183         /* Processor Box hide/shos */
184         toggle_processorbox_button.set_text (_("Processors"));
185         toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
186         set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
187
188         proctoggle = ActionManager::get_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
189         assert(proctoggle);
190         toggle_processorbox_button.set_related_action (proctoggle);
191
192         /* Knobs */
193         Label* solo_boost_label;
194         Label* solo_cut_label;
195         Label* dim_label;
196
197         /* Solo Boost Knob */
198
199         solo_boost_control = new ArdourKnob ();
200         solo_boost_control->set_name("monitor section knob");
201         solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
202         set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
203
204         solo_boost_display = new ArdourDisplay ();
205         solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
206         solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
207         solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
208         solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
209         solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
210
211         solo_boost_label = manage (new Label (_("Solo Boost")));
212
213         /* Solo (SiP) cut */
214
215         solo_cut_control = new ArdourKnob ();
216         solo_cut_control->set_name ("monitor section knob");
217         solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
218         set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
219
220         solo_cut_display = new ArdourDisplay ();
221         solo_cut_display->set_name("monitor section dropdown"); // XXX
222         solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
223         solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
224         solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
225         solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
226         solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
227         solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
228
229         solo_cut_label = manage (new Label (_("SiP Cut")));
230
231         /* Dim */
232
233         dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
234         dim_control->set_name ("monitor section knob");
235         dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
236         set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
237
238         dim_display = new ArdourDisplay ();
239         dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
240         dim_display->add_controllable_preset(_("0 dB"), 0.0);
241         dim_display->add_controllable_preset(_("-3 dB"), -3.0);
242         dim_display->add_controllable_preset(_("-6 dB"), -6.0);
243         dim_display->add_controllable_preset(_("-12 dB"), -12.0);
244         dim_display->add_controllable_preset(_("-20 dB"), -20.0);
245
246         dim_label = manage (new Label (_("Dim")));
247
248         // mute button
249         cut_all_button.set_text (_("Mute"));
250         cut_all_button.set_name ("mute button");
251         cut_all_button.set_size_request (-1, PX_SCALE(30));
252         cut_all_button.show ();
253
254         act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
255         if (act) {
256                 cut_all_button.set_related_action (act);
257         }
258
259         // dim button
260         dim_all_button.set_text (_("Dim"));
261         dim_all_button.set_name ("monitor section dim");
262         dim_all_button.set_size_request (-1, PX_SCALE(25));
263         act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
264         if (act) {
265                 dim_all_button.set_related_action (act);
266         }
267
268         // mono button
269         mono_button.set_text (_("Mono"));
270         mono_button.set_name ("monitor section mono");
271         mono_button.set_size_request (-1, PX_SCALE(25));
272         act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
273         if (act) {
274                 mono_button.set_related_action (act);
275         }
276
277         /* Gain */
278
279         gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
280         gain_control->set_name("monitor section knob");
281         gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
282
283         gain_display = new ArdourDisplay ();
284         gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
285         gain_display->add_controllable_preset(_("0 dB"), 0.0);
286         gain_display->add_controllable_preset(_("-3 dB"), -3.0);
287         gain_display->add_controllable_preset(_("-6 dB"), -6.0);
288         gain_display->add_controllable_preset(_("-12 dB"), -12.0);
289         gain_display->add_controllable_preset(_("-20 dB"), -20.0);
290         gain_display->add_controllable_preset(_("-30 dB"), -30.0);
291
292         Label* output_label = manage (new Label (_("Output")));
293         output_label->set_name (X_("MonitorSectionLabel"));
294
295         output_button = new ArdourButton ();
296         output_button->set_text (_("Output"));
297         output_button->set_name (X_("monitor section cut")); // XXX
298         output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
299         output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
300
301         channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
302         channel_table_scroller.set_size_request (-1, PX_SCALE(150));
303         channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
304         channel_table_scroller.show ();
305         channel_table_scroller.add (channel_table_viewport);
306
307         channel_size_group  = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
308         channel_size_group->add_widget (channel_table_header);
309         channel_size_group->add_widget (channel_table);
310
311         channel_table_header.resize (1, 5);
312
313         Label* l1 = manage (new Label (X_("  ")));
314         l1->set_name (X_("MonitorSectionLabel"));
315         channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
316
317         l1 = manage (new Label (_("Mute")));
318         l1->set_name (X_("MonitorSectionLabel"));
319         channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
320
321         l1 = manage (new Label (_("Dim")));
322         l1->set_name (X_("MonitorSectionLabel"));
323         channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
324
325         l1 = manage (new Label (_("Solo")));
326         l1->set_name (X_("MonitorSectionLabel"));
327         channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
328
329         l1 = manage (new Label (_("Inv")));
330         l1->set_name (X_("MonitorSectionLabel"));
331         channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
332
333         channel_table_header.show ();
334
335
336         /****************************************************************************
337          * LAYOUT  top to bottom
338          */
339
340         // solo, iso information
341         HBox* rude_box = manage (new HBox);
342         rude_box->set_spacing (PX_SCALE(4));
343         rude_box->set_homogeneous (true);
344         rude_box->pack_start (rude_solo_button, true, true);
345         rude_box->pack_start (rude_iso_button, true, true);
346
347         // solo options (right align)
348         HBox* tbx1 = manage (new HBox);
349         tbx1->pack_end (exclusive_solo_button, false, false);
350
351         HBox* tbx2 = manage (new HBox);
352         tbx2->pack_end (solo_mute_override_button, false, false);
353
354         HBox* tbx3 = manage (new HBox);
355         tbx3->pack_end (toggle_processorbox_button, false, false);
356
357         HBox* tbx0 = manage (new HBox); // space
358
359         // combined solo mode (Sip, AFL, PFL) & solo options
360         Table *solo_tbl = manage (new Table);
361         solo_tbl->attach (solo_in_place_button,   0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
362         solo_tbl->attach (pfl_button,             0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
363         solo_tbl->attach (afl_button,             0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
364         solo_tbl->attach (*tbx0,                  1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
365         solo_tbl->attach (*tbx1,                  2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
366         solo_tbl->attach (*tbx2,                  2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
367         solo_tbl->attach (*tbx3,                  2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
368
369         // boost, cut, dim  volume control
370         Table *level_tbl = manage (new Table);
371         level_tbl->attach (*solo_boost_label,    0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
372         level_tbl->attach (*solo_boost_control,  0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
373         level_tbl->attach (*solo_boost_display,  0, 2, 2, 3, EXPAND     , SHRINK, 1, 2);
374
375         level_tbl->attach (*solo_cut_label,      2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
376         level_tbl->attach (*solo_cut_control,    2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
377         level_tbl->attach (*solo_cut_display,    2, 4, 2, 3, EXPAND     , SHRINK, 1, 2);
378
379         level_tbl->attach (*dim_label,           1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
380         level_tbl->attach (*dim_control,         1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
381         level_tbl->attach (*dim_display,         1, 3, 5, 6, EXPAND     , SHRINK, 1, 2);
382
383         /* note that we don't pack the table_hpacker till later
384          * -> top level channel_table_packer */
385         table_hpacker.pack_start (channel_table, true, true);
386
387         // mono, dim
388         HBox* mono_dim_box = manage (new HBox);
389         mono_dim_box->set_spacing (PX_SCALE(4));
390         mono_dim_box->set_homogeneous (true);
391         mono_dim_box->pack_start (mono_button, true, true);
392         mono_dim_box->pack_end (dim_all_button, true, true);
393
394         // master gain 
395         Label* spin_label = manage (new Label (_("Monitor")));
396         VBox* spin_packer = manage (new VBox);
397         spin_packer->set_spacing (PX_SCALE(2));
398         spin_packer->pack_start (*spin_label, false, false);
399         spin_packer->pack_start (*gain_control, false, false);
400         spin_packer->pack_start (*gain_display, false, false);
401
402         master_packer.pack_start (*spin_packer, true, false);
403
404         // combined gain section (channels, mute, dim)
405         VBox* lower_packer = manage (new VBox);
406         lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
407         lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
408         lower_packer->pack_start (*mono_dim_box,        false, false, PX_SCALE(2));
409         lower_packer->pack_start (cut_all_button,       false, false, PX_SCALE(2));
410
411                 // output port select
412         VBox* out_packer = manage (new VBox);
413         out_packer->set_spacing (PX_SCALE(2));
414         out_packer->pack_start (*output_label, false, false);
415         out_packer->pack_start (*output_button, false, false);
416
417         /****************************************************************************
418          * TOP LEVEL LAYOUT
419          */
420         vpacker.set_border_width (PX_SCALE(3));
421         vpacker.pack_start (*rude_box,            false, false, PX_SCALE(3));
422         vpacker.pack_start (rude_audition_button, false, false, 0);
423         vpacker.pack_start (*solo_tbl,            false, false, PX_SCALE(8));
424         vpacker.pack_start (*insert_box,          true,  true,  PX_SCALE(8));
425         vpacker.pack_start (*level_tbl,           false, false, PX_SCALE(8));
426         vpacker.pack_start (*lower_packer,        false, false, PX_SCALE(8));
427         vpacker.pack_start (master_packer,        false, false, PX_SCALE(10));
428         vpacker.pack_end   (*out_packer,          false, false, PX_SCALE(3));
429
430         hpacker.set_spacing (0);
431         hpacker.pack_start (vpacker, true, true);
432
433         gain_control->show_all ();
434         gain_display->show_all ();
435         dim_control->show_all ();
436         dim_display->show_all();
437         solo_boost_control->show_all ();
438         solo_boost_display->show_all();
439
440         mono_dim_box->show ();
441         spin_packer->show ();
442         master_packer.show ();
443         channel_table.show ();
444
445         rude_box->show();
446         solo_tbl->show_all();
447         level_tbl->show();
448         lower_packer->show ();
449         out_packer->show ();
450
451         vpacker.show ();
452         hpacker.show ();
453
454         populate_buttons ();
455         map_state ();
456         assign_controllables ();
457
458         output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
459         output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
460
461         _tearoff = new TearOff (hpacker);
462
463         if (!UIConfiguration::instance().get_floating_monitor_section()) {
464                 /* if torn off, make this a normal window
465                  * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
466                  */
467                 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
468         }
469         _tearoff->tearoff_window().set_title (X_("Monitor"));
470         _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
471
472         update_output_display ();
473         update_processor_box ();
474         _ui_initialized = true;
475
476         /* catch changes that affect us */
477         AudioEngine::instance()->PortConnectedOrDisconnected.connect (
478                 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
479                 );
480         Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
481 }
482
483 MonitorSection::~MonitorSection ()
484 {
485         for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
486                 delete *i;
487         }
488
489         _channel_buttons.clear ();
490         _output_changed_connection.disconnect ();
491
492         delete insert_box;
493         delete output_button;
494         delete gain_control;
495         delete gain_display;
496         delete dim_control;
497         delete dim_display;
498         delete solo_boost_control;
499         delete solo_boost_display;
500         delete solo_cut_control;
501         delete solo_cut_display;
502         delete _tearoff;
503         delete _output_selector;
504         _output_selector = 0;
505 }
506
507
508 void
509 MonitorSection::update_processor_box ()
510 {
511         bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
512
513         if (count_processors () > 0 && !show_processor_box) {
514                 toggle_processorbox_button.set_name (X_("monitor section processors present"));
515         } else {
516                 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
517         }
518
519         if (insert_box->is_visible() == show_processor_box) {
520                 return;
521         }
522
523         if (show_processor_box) {
524                 if (master_packer.get_parent()) {
525                         master_packer.get_parent()->remove (master_packer);
526                 }
527                 insert_box->show();
528                 vpacker.pack_start (master_packer,        false, false, PX_SCALE(10));
529         } else {
530                 if (master_packer.get_parent()) {
531                         master_packer.get_parent()->remove (master_packer);
532                 }
533                 insert_box->hide();
534                 vpacker.pack_start (master_packer,        true,  false, PX_SCALE(10));
535         }
536 }
537
538 void
539 MonitorSection::set_session (Session* s)
540 {
541         AxisView::set_session (s);
542         _plugin_selector->set_session (_session);
543
544         if (_session) {
545
546                 _route = _session->monitor_out ();
547
548                 if (_route) {
549                         /* session with monitor section */
550                         _monitor = _route->monitor_control ();
551                         assign_controllables ();
552                         _route->output()->changed.connect (_output_changed_connection, invalidator (*this),
553                                                                                         boost::bind (&MonitorSection::update_output_display, this),
554                                                                                         gui_context());
555                         insert_box->set_route (_route);
556                         _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
557                         if (_ui_initialized) {
558                                 update_processor_box ();
559                         }
560                 } else {
561                         /* session with no monitor section */
562                         _output_changed_connection.disconnect();
563                         _monitor.reset ();
564                         _route.reset ();
565                         delete _output_selector;
566                         _output_selector = 0;
567                 }
568
569                 if (channel_table_scroller.get_parent()) {
570                         /* scroller is packed, so remove it */
571                         channel_table_packer.remove (channel_table_scroller);
572                 }
573
574                 if (table_hpacker.get_parent () == &channel_table_packer) {
575                         /* this occurs when the table hpacker is directly
576                                  packed, so remove it.
577                                  */
578                         channel_table_packer.remove (table_hpacker);
579                 } else if (table_hpacker.get_parent()) {
580                         channel_table_viewport.remove ();
581                 }
582
583                 if (_monitor->output_streams().n_audio() > 7) {
584                         /* put the table into a scrolled window, and then put
585                          * that into the channel vpacker, after the table header
586                          */
587                         channel_table_viewport.add (table_hpacker);
588                         channel_table_packer.pack_start (channel_table_scroller, true, true);
589                         channel_table_viewport.show ();
590                         channel_table_scroller.show ();
591
592                 } else {
593                         /* just put the channel table itself into the channel
594                          * vpacker, after the table header
595                          */
596
597                         channel_table_packer.pack_start (table_hpacker, true, true);
598                         channel_table_scroller.hide ();
599                 }
600
601                 table_hpacker.show ();
602                 channel_table.show ();
603
604         } else {
605                 /* no session */
606
607                 _output_changed_connection.disconnect();
608                 _monitor.reset ();
609                 _route.reset ();
610                 control_connections.drop_connections ();
611                 rude_iso_button.unset_active_state ();
612                 rude_solo_button.unset_active_state ();
613                 delete _output_selector;
614                 _output_selector = 0;
615
616                 assign_controllables ();
617         }
618 }
619
620 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
621 {
622         cut.set_name (X_("mute button"));
623         dim.set_name (X_("monitor section dim"));
624         solo.set_name (X_("solo button"));
625         invert.set_name (X_("invert button"));
626
627         cut.unset_flags (Gtk::CAN_FOCUS);
628         dim.unset_flags (Gtk::CAN_FOCUS);
629         solo.unset_flags (Gtk::CAN_FOCUS);
630         invert.unset_flags (Gtk::CAN_FOCUS);
631 }
632
633         void
634 MonitorSection::populate_buttons ()
635 {
636         if (!_monitor) {
637                 return;
638         }
639
640         Glib::RefPtr<Action> act;
641         uint32_t nchans = _monitor->output_streams().n_audio();
642
643         channel_table.resize (nchans, 5);
644         channel_table.set_col_spacings (6);
645         channel_table.set_row_spacings (6);
646         channel_table.set_homogeneous (true);
647
648         const uint32_t row_offset = 0;
649
650         for (uint32_t i = 0; i < nchans; ++i) {
651
652                 string l;
653                 char buf[64];
654
655                 if (nchans == 2) {
656                         if (i == 0) {
657                                 l = "L";
658                         } else {
659                                 l = "R";
660                         }
661                 } else {
662                         char buf[32];
663                         snprintf (buf, sizeof (buf), "%d", i+1);
664                         l = buf;
665                 }
666
667                 Label* label = manage (new Label (l));
668                 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
669
670                 ChannelButtonSet* cbs = new ChannelButtonSet;
671
672                 _channel_buttons.push_back (cbs);
673
674                 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
675                 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
676                 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
677                 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
678
679                 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
680                 act = ActionManager::get_action (X_("Monitor"), buf);
681                 if (act) {
682                         cbs->cut.set_related_action (act);
683                 }
684
685                 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
686                 act = ActionManager::get_action (X_("Monitor"), buf);
687                 if (act) {
688                         cbs->dim.set_related_action (act);
689                 }
690
691                 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
692                 act = ActionManager::get_action (X_("Monitor"), buf);
693                 if (act) {
694                         cbs->solo.set_related_action (act);
695                 }
696
697                 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
698                 act = ActionManager::get_action (X_("Monitor"), buf);
699                 if (act) {
700                         cbs->invert.set_related_action (act);
701                 }
702         }
703
704         channel_table.show_all ();
705 }
706
707 void
708 MonitorSection::toggle_exclusive_solo ()
709 {
710         if (!_monitor) {
711                 return;
712         }
713
714         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
715         if (act) {
716                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
717                 Config->set_exclusive_solo (tact->get_active());
718         }
719
720 }
721
722 void
723 MonitorSection::toggle_mute_overrides_solo ()
724 {
725         if (!_monitor) {
726                 return;
727         }
728
729         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
730         if (act) {
731                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
732                 Config->set_solo_mute_override (tact->get_active());
733         }
734 }
735
736 void
737 MonitorSection::dim_all ()
738 {
739         if (!_monitor) {
740                 return;
741         }
742
743         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
744         if (act) {
745                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
746                 _monitor->set_dim_all (tact->get_active());
747         }
748
749 }
750
751 void
752 MonitorSection::cut_all ()
753 {
754         if (!_monitor) {
755                 return;
756         }
757
758         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
759         if (act) {
760                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
761                 _monitor->set_cut_all (tact->get_active());
762         }
763 }
764
765 void
766 MonitorSection::mono ()
767 {
768         if (!_monitor) {
769                 return;
770         }
771
772         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
773         if (act) {
774                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
775                 _monitor->set_mono (tact->get_active());
776         }
777 }
778
779 void
780 MonitorSection::cut_channel (uint32_t chn)
781 {
782         if (!_monitor) {
783                 return;
784         }
785
786         char buf[64];
787         snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
788
789         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
790         if (act) {
791                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
792                 _monitor->set_cut (chn, tact->get_active());
793         }
794 }
795
796 void
797 MonitorSection::dim_channel (uint32_t chn)
798 {
799         if (!_monitor) {
800                 return;
801         }
802
803         char buf[64];
804         snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
805
806         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
807         if (act) {
808                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
809                 _monitor->set_dim (chn, tact->get_active());
810         }
811
812 }
813
814 void
815 MonitorSection::solo_channel (uint32_t chn)
816 {
817         if (!_monitor) {
818                 return;
819         }
820
821         char buf[64];
822         snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
823
824         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
825         if (act) {
826                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
827                 _monitor->set_solo (chn, tact->get_active());
828         }
829
830 }
831
832 void
833 MonitorSection::invert_channel (uint32_t chn)
834 {
835         if (!_monitor) {
836                 return;
837         }
838
839         char buf[64];
840         snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
841
842         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
843         if (act) {
844                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
845                 _monitor->set_polarity (chn, tact->get_active());
846         }
847 }
848
849 void
850 MonitorSection::register_actions ()
851 {
852         string action_name;
853         string action_descr;
854         Glib::RefPtr<Action> act;
855
856         monitor_actions = myactions.create_action_group (X_("Monitor"));
857
858         myactions.register_toggle_action (monitor_actions, "monitor-mono", _("Switch monitor to mono"),
859                         sigc::mem_fun (*this, &MonitorSection::mono));
860
861         myactions.register_toggle_action (monitor_actions, "monitor-cut-all", _("Cut monitor"),
862                         sigc::mem_fun (*this, &MonitorSection::cut_all));
863
864         myactions.register_toggle_action (monitor_actions, "monitor-dim-all", _("Dim monitor"),
865                         sigc::mem_fun (*this, &MonitorSection::dim_all));
866
867         act = myactions.register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
868                         sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
869
870         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
871         tact->set_active (Config->get_exclusive_solo());
872
873         act = myactions.register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
874                         sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
875
876         tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
877         tact->set_active (Config->get_solo_mute_override());
878
879         for (uint32_t chn = 0; chn < 16; ++chn) {
880
881                 action_name = string_compose (X_("monitor-cut-%1"), chn);
882                 action_descr = string_compose (_("Cut monitor channel %1"), chn);
883                 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
884                                 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
885
886                 action_name = string_compose (X_("monitor-dim-%1"), chn);
887                 action_descr = string_compose (_("Dim monitor channel %1"), chn);
888                 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
889                                 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
890
891                 action_name = string_compose (X_("monitor-solo-%1"), chn);
892                 action_descr = string_compose (_("Solo monitor channel %1"), chn);
893                 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
894                                 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
895
896                 action_name = string_compose (X_("monitor-invert-%1"), chn);
897                 action_descr = string_compose (_("Invert monitor channel %1"), chn);
898                 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
899                                 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
900
901         }
902
903
904         Glib::RefPtr<ActionGroup> solo_actions = myactions.create_action_group (X_("Solo"));
905         RadioAction::Group solo_group;
906
907         myactions.register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
908                         sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
909         myactions.register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
910                         sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
911         myactions.register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
912                         sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
913
914         proctoggle = myactions.register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
915                         sigc::mem_fun(*this, &MonitorSection::update_processor_box));
916 }
917
918 void
919 MonitorSection::connect_actions ()
920 {
921         Glib::RefPtr<Action> act;
922         Glib::RefPtr<ToggleAction> tact;
923
924 #define MON_TOG(NAME, FUNC) \
925         act = ActionManager::get_action (X_("Monitor"), NAME); \
926         tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act); \
927         assert (tact); \
928         tact->signal_toggled().connect (sigc::mem_fun (*this, &MonitorSection::FUNC)); \
929
930         MON_TOG("monitor-mono", mono);
931         MON_TOG("monitor-cut-all", cut_all);
932         MON_TOG("monitor-dim-all", dim_all);
933
934         MON_TOG("toggle-exclusive-solo", toggle_exclusive_solo);
935         tact->set_active (Config->get_exclusive_solo());
936
937         MON_TOG("toggle-mute-overrides-solo", toggle_mute_overrides_solo);
938         tact->set_active (Config->get_solo_mute_override());
939 #undef MON_TOG
940
941 #define MON_BIND(NAME, FUNC, ARG) \
942         act = ActionManager::get_action (X_("Monitor"), NAME); \
943         tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act); \
944         assert (tact); \
945         tact->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &MonitorSection::FUNC), ARG));
946
947         for (uint32_t chn = 0; chn < 16; ++chn) {
948                 std::string action_name = string_compose (X_("monitor-cut-%1"), chn);
949                 MON_BIND(action_name.c_str(), cut_channel, chn);
950                 action_name = string_compose (X_("monitor-dim-%1"), chn);
951                 MON_BIND(action_name.c_str(), dim_channel, chn);
952                 action_name = string_compose (X_("monitor-solo-%1"), chn);
953                 MON_BIND(action_name.c_str(), solo_channel, chn);
954                 action_name = string_compose (X_("monitor-invert-%1"), chn);
955                 MON_BIND(action_name.c_str(), invert_channel, chn);
956         }
957 #undef MON_BIND
958
959 #define SOLO_RADIO(NAME, FUNC) \
960         act = ActionManager::get_action (X_("Solo"), NAME); \
961         ract = Glib::RefPtr<RadioAction>::cast_dynamic (act); \
962         assert (ract); \
963         ract->signal_toggled().connect (sigc::mem_fun (*this, &MonitorSection::FUNC)); \
964
965         Glib::RefPtr<RadioAction> ract;
966         SOLO_RADIO ("solo-use-in-place", solo_use_in_place);
967         SOLO_RADIO ("solo-use-afl", solo_use_afl);
968         SOLO_RADIO ("solo-use-pfl", solo_use_pfl);
969 #undef SOLO_RADIO
970 }
971
972 void
973 MonitorSection::solo_use_in_place ()
974 {
975         /* this is driven by a toggle on a radio group, and so is invoked twice,
976                  once for the item that became inactive and once for the one that became
977                  active.
978                  */
979
980         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
981
982         if (act) {
983                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
984                 if (ract) {
985                         if (!ract->get_active ()) {
986                                 /* We are turning SiP off, which means that AFL or PFL will be turned on
987                                          shortly; don't update the solo model in the mean time, as if the currently
988                                          configured listen position is not the one that is about to be turned on,
989                                          things will go wrong.
990                                          */
991                                 _inhibit_solo_model_update = true;
992                         }
993                         Config->set_solo_control_is_listen_control (!ract->get_active());
994                         _inhibit_solo_model_update = false;
995                 }
996         }
997 }
998
999 void
1000 MonitorSection::solo_use_afl ()
1001 {
1002         /* this is driven by a toggle on a radio group, and so is invoked twice,
1003                  once for the item that became inactive and once for the one that became
1004                  active.
1005                  */
1006
1007         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1008         if (act) {
1009                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1010                 if (ract) {
1011                         if (ract->get_active()) {
1012                                 Config->set_solo_control_is_listen_control (true);
1013                                 Config->set_listen_position (AfterFaderListen);
1014                         }
1015                 }
1016         }
1017 }
1018
1019 void
1020 MonitorSection::solo_use_pfl ()
1021 {
1022         /* this is driven by a toggle on a radio group, and so is invoked twice,
1023            once for the item that became inactive and once for the one that became
1024            active.
1025         */
1026
1027         Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1028         if (act) {
1029                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1030                 if (ract) {
1031                         if (ract->get_active()) {
1032                                 Config->set_solo_control_is_listen_control (true);
1033                                 Config->set_listen_position (PreFaderListen);
1034                         }
1035                 }
1036         }
1037 }
1038
1039 void
1040 MonitorSection::update_solo_model ()
1041 {
1042         if (_inhibit_solo_model_update) {
1043                 return;
1044         }
1045
1046         const char* action_name = 0;
1047         Glib::RefPtr<Action> act;
1048
1049         if (Config->get_solo_control_is_listen_control()) {
1050                 switch (Config->get_listen_position()) {
1051                         case AfterFaderListen:
1052                                 action_name = X_("solo-use-afl");
1053                                 break;
1054                         case PreFaderListen:
1055                                 action_name = X_("solo-use-pfl");
1056                                 break;
1057                 }
1058         } else {
1059                 action_name = X_("solo-use-in-place");
1060         }
1061
1062         act = ActionManager::get_action (X_("Solo"), action_name);
1063         if (act) {
1064
1065                 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1066                 if (ract) {
1067                         /* because these are radio buttons, one of them will be
1068                                  active no matter what. to trigger a change in the
1069                                  action so that the view picks it up, toggle it.
1070                                  */
1071                         if (ract->get_active()) {
1072                                 ract->set_active (false);
1073                         }
1074                         ract->set_active (true);
1075                 }
1076
1077         }
1078 }
1079
1080 void
1081 MonitorSection::map_state ()
1082 {
1083         if (!_route || !_monitor) {
1084                 return;
1085         }
1086
1087         Glib::RefPtr<Action> act;
1088
1089         update_solo_model ();
1090
1091         act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1092         if (act) {
1093                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1094                 if (tact) {
1095                         tact->set_active (_monitor->cut_all());
1096                 }
1097         }
1098
1099         act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1100         if (act) {
1101                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1102                 if (tact) {
1103                         tact->set_active (_monitor->dim_all());
1104                 }
1105         }
1106
1107         act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1108         if (act) {
1109                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1110                 if (tact) {
1111                         tact->set_active (_monitor->mono());
1112                 }
1113         }
1114
1115         uint32_t nchans = _monitor->output_streams().n_audio();
1116
1117         assert (nchans == _channel_buttons.size ());
1118
1119         for (uint32_t n = 0; n < nchans; ++n) {
1120
1121                 char action_name[32];
1122
1123                 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1124                 act = ActionManager::get_action (X_("Monitor"), action_name);
1125                 if (act) {
1126                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1127                         if (tact) {
1128                                 tact->set_active (_monitor->cut (n));
1129                         }
1130                 }
1131
1132                 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1133                 act = ActionManager::get_action (X_("Monitor"), action_name);
1134                 if (act) {
1135                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1136                         if (tact) {
1137                                 tact->set_active (_monitor->dimmed (n));
1138                         }
1139                 }
1140
1141                 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1142                 act = ActionManager::get_action (X_("Monitor"), action_name);
1143                 if (act) {
1144                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1145                         if (tact) {
1146                                 tact->set_active (_monitor->soloed (n));
1147                         }
1148                 }
1149
1150                 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1151                 act = ActionManager::get_action (X_("Monitor"), action_name);
1152                 if (act) {
1153                         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1154                         if (tact) {
1155                                 tact->set_active (_monitor->inverted (n));
1156                         }
1157                 }
1158         }
1159 }
1160
1161 void
1162 MonitorSection::do_blink (bool onoff)
1163 {
1164         solo_blink (onoff);
1165         audition_blink (onoff);
1166 }
1167
1168 void
1169 MonitorSection::audition_blink (bool onoff)
1170 {
1171         if (_session == 0) {
1172                 return;
1173         }
1174
1175         if (_session->is_auditioning()) {
1176                 rude_audition_button.set_active (onoff);
1177         } else {
1178                 rude_audition_button.set_active (false);
1179         }
1180 }
1181
1182 void
1183 MonitorSection::solo_blink (bool onoff)
1184 {
1185         if (_session == 0) {
1186                 return;
1187         }
1188
1189         if (_session->soloing() || _session->listening()) {
1190                 rude_solo_button.set_active (onoff);
1191
1192                 if (_session->soloing()) {
1193                         if (_session->solo_isolated()) {
1194                                 rude_iso_button.set_active (onoff);
1195                         } else {
1196                                 rude_iso_button.set_active (false);
1197                         }
1198                 }
1199
1200         } else {
1201                 rude_solo_button.set_active (false);
1202                 rude_iso_button.set_active (false);
1203         }
1204 }
1205
1206 bool
1207 MonitorSection::cancel_isolate (GdkEventButton*)
1208 {
1209         if (_session) {
1210                 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1211                 _session->set_solo_isolated (rl, false, Session::rt_cleanup, Controllable::NoGroup);
1212         }
1213
1214         return true;
1215 }
1216
1217 bool
1218 MonitorSection::cancel_audition (GdkEventButton*)
1219 {
1220         if (_session) {
1221                 _session->cancel_audition();
1222         }
1223         return true;
1224 }
1225
1226 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1227         if (action) { \
1228                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1229                 if (tact && tact->get_active() != value) { \
1230                         tact->set_active(value); \
1231                 } \
1232         }
1233
1234 void
1235 MonitorSection::parameter_changed (std::string name)
1236 {
1237         if (name == "solo-control-is-listen-control") {
1238                 update_solo_model ();
1239         } else if (name == "listen-position") {
1240                 update_solo_model ();
1241         } else if (name == "solo-mute-override") {
1242                 SYNCHRONIZE_TOGGLE_ACTION(
1243                                 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1244                                 Config->get_solo_mute_override ())
1245         } else if (name == "exclusive-solo") {
1246                 SYNCHRONIZE_TOGGLE_ACTION(
1247                                 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1248                                 Config->get_exclusive_solo ())
1249         }
1250 }
1251
1252 void
1253 MonitorSection::assign_controllables ()
1254 {
1255         boost::shared_ptr<Controllable> none;
1256
1257         if (!gain_control) {
1258                 /* too early - GUI controls not set up yet */
1259                 return;
1260         }
1261
1262         if (_session) {
1263                 solo_cut_control->set_controllable (_session->solo_cut_control());
1264                 solo_cut_display->set_controllable (_session->solo_cut_control());
1265         } else {
1266                 solo_cut_control->set_controllable (none);
1267                 solo_cut_display->set_controllable (none);
1268         }
1269
1270         if (_route) {
1271                 gain_control->set_controllable (_route->gain_control());
1272                 gain_display->set_controllable (_route->gain_control());
1273         } else {
1274                 gain_control->set_controllable (none);
1275         }
1276
1277         if (_monitor) {
1278
1279                 cut_all_button.set_controllable (_monitor->cut_control());
1280                 cut_all_button.watch ();
1281                 dim_all_button.set_controllable (_monitor->dim_control());
1282                 dim_all_button.watch ();
1283                 mono_button.set_controllable (_monitor->mono_control());
1284                 mono_button.watch ();
1285
1286                 dim_control->set_controllable (_monitor->dim_level_control ());
1287                 dim_display->set_controllable (_monitor->dim_level_control ());
1288                 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1289                 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1290
1291         } else {
1292
1293                 cut_all_button.set_controllable (none);
1294                 dim_all_button.set_controllable (none);
1295                 mono_button.set_controllable (none);
1296
1297                 dim_control->set_controllable (none);
1298                 dim_display->set_controllable (none);
1299                 solo_boost_control->set_controllable (none);
1300                 solo_boost_display->set_controllable (none);
1301         }
1302 }
1303
1304 string
1305 MonitorSection::state_id() const
1306 {
1307         return "monitor-section";
1308 }
1309
1310 void
1311 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1312 {
1313         using namespace Menu_Helpers;
1314
1315         if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1316                 return;
1317         }
1318
1319         list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1320         while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1321                 ++i;
1322         }
1323
1324         if (i != output_menu_bundles.end()) {
1325                 return;
1326         }
1327
1328         output_menu_bundles.push_back (b);
1329
1330         MenuList& citems = output_menu.items();
1331
1332         std::string n = b->name ();
1333         replace_all (n, "_", " ");
1334
1335         citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1336 }
1337
1338 void
1339 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1340 {
1341
1342         ARDOUR::BundleList current = _route->output()->bundles_connected ();
1343
1344         if (std::find (current.begin(), current.end(), c) == current.end()) {
1345                 _route->output()->connect_ports_to_bundle (c, true, this);
1346         } else {
1347                 _route->output()->disconnect_ports_from_bundle (c, this);
1348         }
1349 }
1350
1351 gint
1352 MonitorSection::output_release (GdkEventButton *ev)
1353 {
1354         switch (ev->button) {
1355         case 3:
1356                 edit_output_configuration ();
1357                 break;
1358         }
1359
1360         return false;
1361 }
1362
1363 struct RouteCompareByName {
1364         bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1365                 return a->name().compare (b->name()) < 0;
1366         }
1367 };
1368
1369 gint
1370 MonitorSection::output_press (GdkEventButton *ev)
1371 {
1372         using namespace Menu_Helpers;
1373         if (!_session) {
1374                 MessageDialog msg (_("No session - no I/O changes are possible"));
1375                 msg.run ();
1376                 return true;
1377         }
1378
1379         MenuList& citems = output_menu.items();
1380         switch (ev->button) {
1381
1382         case 3:
1383                 return false;  //wait for the mouse-up to pop the dialog
1384
1385         case 1:
1386         {
1387                 output_menu.set_name ("ArdourContextMenu");
1388                 citems.clear ();
1389                 output_menu_bundles.clear ();
1390
1391                 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1392
1393                 citems.push_back (SeparatorElem());
1394                 uint32_t const n_with_separator = citems.size ();
1395
1396                 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1397
1398                 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1399
1400                 /* give user bundles first chance at being in the menu */
1401
1402                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1403                         if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1404                                 maybe_add_bundle_to_output_menu (*i, current);
1405                         }
1406                 }
1407
1408                 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1409                         if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1410                                 maybe_add_bundle_to_output_menu (*i, current);
1411                         }
1412                 }
1413
1414                 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1415                 RouteList copy = *routes;
1416                 copy.sort (RouteCompareByName ());
1417                 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1418                         maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1419                 }
1420
1421                 if (citems.size() == n_with_separator) {
1422                         /* no routes added; remove the separator */
1423                         citems.pop_back ();
1424                 }
1425
1426                 citems.push_back (SeparatorElem());
1427                 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1428
1429                 output_menu.popup (1, ev->time);
1430                 break;
1431         }
1432
1433         default:
1434                 break;
1435         }
1436         return TRUE;
1437 }
1438
1439 void
1440 MonitorSection::update_output_display ()
1441 {
1442         if (!_route || !_monitor || _session->deletion_in_progress()) {
1443                 return;
1444         }
1445
1446         uint32_t io_count;
1447         uint32_t io_index;
1448         boost::shared_ptr<Port> port;
1449         vector<string> port_connections;
1450
1451         uint32_t total_connection_count = 0;
1452         uint32_t io_connection_count = 0;
1453         uint32_t ardour_connection_count = 0;
1454         uint32_t system_connection_count = 0;
1455         uint32_t other_connection_count = 0;
1456
1457         ostringstream label;
1458
1459         bool have_label = false;
1460         bool each_io_has_one_connection = true;
1461
1462         string connection_name;
1463         string ardour_track_name;
1464         string other_connection_type;
1465         string system_ports;
1466         string system_port;
1467
1468         ostringstream tooltip;
1469         char * tooltip_cstr;
1470
1471         io_count = _route->n_outputs().n_total();
1472         tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1473
1474
1475         for (io_index = 0; io_index < io_count; ++io_index) {
1476
1477                 port = _route->output()->nth (io_index);
1478
1479                 //ignore any port connections that don't match our DataType
1480                 if (port->type() != DataType::AUDIO) {
1481                         continue;
1482                 }
1483
1484                 port_connections.clear ();
1485                 port->get_connections(port_connections);
1486                 io_connection_count = 0;
1487
1488                 if (!port_connections.empty()) {
1489                         for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1490                                 string pn = "";
1491                                 string& connection_name (*i);
1492
1493                                 if (connection_name.find("system:") == 0) {
1494                                         pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1495                                 }
1496
1497                                 if (io_connection_count == 0) {
1498                                         tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1499                                                 << " -> "
1500                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1501                                 } else {
1502                                         tooltip << ", "
1503                                                 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1504                                 }
1505
1506                                 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1507                                         if (ardour_track_name.empty()) {
1508                                                 // "ardour:Master/in 1" -> "ardour:Master/"
1509                                                 string::size_type slash = connection_name.find("/");
1510                                                 if (slash != string::npos) {
1511                                                         ardour_track_name = connection_name.substr(0, slash + 1);
1512                                                 }
1513                                         }
1514
1515                                         if (connection_name.find(ardour_track_name) == 0) {
1516                                                 ++ardour_connection_count;
1517                                         }
1518                                 } else if (!pn.empty()) {
1519                                         if (system_ports.empty()) {
1520                                                 system_ports += pn;
1521                                         } else {
1522                                                 system_ports += "/" + pn;
1523                                         }
1524                                         if (connection_name.find("system:") == 0) {
1525                                                 ++system_connection_count;
1526                                         }
1527                                 } else if (connection_name.find("system:") == 0) {
1528                                         // "system:playback_123" -> "123"
1529                                         system_port = connection_name.substr(16);
1530                                         if (system_ports.empty()) {
1531                                                 system_ports += system_port;
1532                                         } else {
1533                                                 system_ports += "/" + system_port;
1534                                         }
1535
1536                                         ++system_connection_count;
1537                                 } else {
1538                                         if (other_connection_type.empty()) {
1539                                                 // "jamin:in 1" -> "jamin:"
1540                                                 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1541                                         }
1542
1543                                         if (connection_name.find(other_connection_type) == 0) {
1544                                                 ++other_connection_count;
1545                                         }
1546                                 }
1547
1548                                 ++total_connection_count;
1549                                 ++io_connection_count;
1550                         }
1551                 }
1552
1553                 if (io_connection_count != 1) {
1554                         each_io_has_one_connection = false;
1555                 }
1556         }
1557
1558         if (total_connection_count == 0) {
1559                 tooltip << endl << _("Disconnected");
1560         }
1561
1562         tooltip_cstr = new char[tooltip.str().size() + 1];
1563         strcpy(tooltip_cstr, tooltip.str().c_str());
1564
1565         set_tooltip (output_button, tooltip_cstr, "");
1566
1567         if (each_io_has_one_connection) {
1568                 if (total_connection_count == ardour_connection_count) {
1569                         // all connections are to the same track in ardour
1570                         // "ardour:Master/" -> "Master"
1571                         string::size_type slash = ardour_track_name.find("/");
1572                         if (slash != string::npos) {
1573                                 label << ardour_track_name.substr(7, slash - 7);
1574                                 have_label = true;
1575                         }
1576                 } else if (total_connection_count == system_connection_count) {
1577                         // all connections are to system ports
1578                         label << system_ports;
1579                         have_label = true;
1580                 } else if (total_connection_count == other_connection_count) {
1581                         // all connections are to the same external program eg jamin
1582                         // "jamin:" -> "jamin"
1583                         label << other_connection_type.substr(0, other_connection_type.size() - 1);
1584                         have_label = true;
1585                 }
1586         }
1587
1588         if (!have_label) {
1589                 if (total_connection_count == 0) {
1590                         // Disconnected
1591                         label << "-";
1592                 } else {
1593                         // Odd configuration
1594                         label << "*" << total_connection_count << "*";
1595                 }
1596         }
1597
1598         output_button->set_text (label.str());
1599 }
1600
1601 void
1602 MonitorSection::disconnect_output ()
1603 {
1604         if (_route) {
1605                 _route->output()->disconnect(this);
1606         }
1607 }
1608
1609 void
1610 MonitorSection::edit_output_configuration ()
1611 {
1612         if (_output_selector == 0) {
1613                 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1614         }
1615         _output_selector->present ();
1616 }
1617
1618 void
1619 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1620 {
1621         if (!_route) {
1622                 return;
1623         }
1624         boost::shared_ptr<Port> a = wa.lock ();
1625         boost::shared_ptr<Port> b = wb.lock ();
1626         if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1627                 update_output_display ();
1628         }
1629 }
1630
1631 void
1632 MonitorSection::load_bindings ()
1633 {
1634         bindings = Bindings::get_bindings (X_("monitor-section"), myactions);
1635 }
1636
1637 void
1638 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1639 {
1640         boost::shared_ptr<Processor> processor (p.lock ());
1641         if (!processor || !processor->display_to_user()) {
1642                 return;
1643         }
1644         if (boost::dynamic_pointer_cast<Amp>(processor)) {
1645                 return;
1646         }
1647         ++(*cnt);
1648 }
1649
1650 uint32_t
1651 MonitorSection::count_processors ()
1652 {
1653         uint32_t processor_count = 0;
1654         if (_route) {
1655                 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1656         }
1657         return processor_count;
1658 }
1659
1660 void
1661 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1662 {
1663         update_processor_box ();
1664 }