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